You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ol...@apache.org on 2020/05/20 20:53:54 UTC

[maven-invoker-plugin] branch master updated: [MINVOKER-250] streamLogsOnFailures

This is an automated email from the ASF dual-hosted git repository.

olamy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-invoker-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new 1c55108  [MINVOKER-250] streamLogsOnFailures
1c55108 is described below

commit 1c55108ecbde03bf615fd490a5c63b2fd3d6b421
Author: Slawomir Jaranowski <s....@gmail.com>
AuthorDate: Sat Mar 28 11:51:51 2020 +0100

    [MINVOKER-250] streamLogsOnFailures
---
 pom.xml                                            |   3 +
 .../invoker.properties                             |  18 ++++
 src/it/fail-build-streamLogsOnFailures/pom.xml     |  64 ++++++++++++
 .../src/it/project/pom.xml                         |  35 +++++++
 .../fail-build-streamLogsOnFailures/verify.groovy  |  29 ++++++
 .../invoker.properties                             |  18 ++++
 .../pom.xml                                        |  65 ++++++++++++
 .../src/it/project/pom.xml                         |  35 +++++++
 .../verify.groovy                                  |  31 ++++++
 .../maven/plugins/invoker/AbstractInvokerMojo.java |  74 ++++++-------
 .../apache/maven/plugins/invoker/InvokerMojo.java  |  13 +++
 .../maven/plugins/invoker/InvokerSession.java      | 114 ++++++++++++++++-----
 .../apache/maven/plugins/invoker/VerifyMojo.java   |  13 +++
 src/main/mdo/invocation.mdo                        |   7 ++
 src/site/apt/examples/logs-for-failed-tests.apt.vm |  56 ++++++++++
 src/site/site.xml                                  |   1 +
 16 files changed, 510 insertions(+), 66 deletions(-)

diff --git a/pom.xml b/pom.xml
index 3adbc7c..a6be5ad 100644
--- a/pom.xml
+++ b/pom.xml
@@ -336,6 +336,9 @@ under the License.
                   <maven.compiler.source>${maven.compiler.source}</maven.compiler.source>
                   <maven.compiler.target>${maven.compiler.target}</maven.compiler.target>
                 </properties>
+                <scriptVariables>
+                  <projectVersion>${project.version}</projectVersion>
+                </scriptVariables>
                 <goals>
                   <goal>clean</goal>
                   <goal>initialize</goal>
diff --git a/src/it/fail-build-streamLogsOnFailures/invoker.properties b/src/it/fail-build-streamLogsOnFailures/invoker.properties
new file mode 100644
index 0000000..e64d99e
--- /dev/null
+++ b/src/it/fail-build-streamLogsOnFailures/invoker.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+invoker.buildResult = failure
diff --git a/src/it/fail-build-streamLogsOnFailures/pom.xml b/src/it/fail-build-streamLogsOnFailures/pom.xml
new file mode 100644
index 0000000..49ec32d
--- /dev/null
+++ b/src/it/fail-build-streamLogsOnFailures/pom.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.plugins.invoker</groupId>
+  <artifactId>fail-build-streamLogsOnFailures</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <description>Test to check that a failure in the forked Maven build fails the parent build with streamed logs.</description>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-invoker-plugin</artifactId>
+        <version>@pom.version@</version>
+        <configuration>
+          <writeJunitReport>true</writeJunitReport>
+          <debug>false</debug>
+          <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+          <pomIncludes>
+            <pomInclude>*/pom.xml</pomInclude>
+          </pomIncludes>
+          <streamLogsOnFailures>true</streamLogsOnFailures>
+        </configuration>
+        <executions>
+          <execution>
+            <id>integration-test</id>
+            <phase>initialize</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/src/it/fail-build-streamLogsOnFailures/src/it/project/pom.xml b/src/it/fail-build-streamLogsOnFailures/src/it/project/pom.xml
new file mode 100644
index 0000000..cf9bbe9
--- /dev/null
+++ b/src/it/fail-build-streamLogsOnFailures/src/it/project/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <!-- invalid model version to make build fail -->
+  <modelVersion>99.0.0</modelVersion>
+  <groupId>test</groupId>
+  <artifactId>fail-build</artifactId>
+  <version>0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <invalidElementShouldFailBuild/>
+</project>
diff --git a/src/it/fail-build-streamLogsOnFailures/verify.groovy b/src/it/fail-build-streamLogsOnFailures/verify.groovy
new file mode 100644
index 0000000..06e686d
--- /dev/null
+++ b/src/it/fail-build-streamLogsOnFailures/verify.groovy
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+def FS = File.separator
+def buildLogOfProject = new File( basedir, 'target/it/project/build.log' ).text
+
+def buildLog = new File( basedir, 'build.log' ).text
+
+assert buildLog.contains( '*** begin build.log for: project' + FS + 'pom.xml ***' )
+assert buildLog.contains( buildLogOfProject )
+assert buildLog.contains( '*** end build.log for: project' + FS + 'pom.xml ***' )
+
+assert buildLog.contains( 'ERROR] Failed to execute goal org.apache.maven.plugins:maven-invoker-plugin:' + projectVersion + ':run' )
diff --git a/src/it/fail-build-with-verify-streamLogsOnFailures/invoker.properties b/src/it/fail-build-with-verify-streamLogsOnFailures/invoker.properties
new file mode 100644
index 0000000..e64d99e
--- /dev/null
+++ b/src/it/fail-build-with-verify-streamLogsOnFailures/invoker.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+invoker.buildResult = failure
diff --git a/src/it/fail-build-with-verify-streamLogsOnFailures/pom.xml b/src/it/fail-build-with-verify-streamLogsOnFailures/pom.xml
new file mode 100644
index 0000000..e366ff1
--- /dev/null
+++ b/src/it/fail-build-with-verify-streamLogsOnFailures/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.plugins.invoker</groupId>
+  <artifactId>fail-build-with-verify-streamLogsOnFailures</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <description>Test to check that a failure in the forked Maven build fails the parent build with streamed logs.</description>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-invoker-plugin</artifactId>
+        <version>@project.version@</version>
+        <configuration>
+          <writeJunitReport>true</writeJunitReport>
+          <debug>false</debug>
+          <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+          <pomIncludes>
+            <pomInclude>*/pom.xml</pomInclude>
+          </pomIncludes>
+          <streamLogsOnFailures>true</streamLogsOnFailures>
+        </configuration>
+        <executions>
+          <execution>
+            <id>integration-test</id>
+            <phase>initialize</phase>
+            <goals>
+              <goal>integration-test</goal>
+              <goal>verify</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/src/it/fail-build-with-verify-streamLogsOnFailures/src/it/project/pom.xml b/src/it/fail-build-with-verify-streamLogsOnFailures/src/it/project/pom.xml
new file mode 100644
index 0000000..cf9bbe9
--- /dev/null
+++ b/src/it/fail-build-with-verify-streamLogsOnFailures/src/it/project/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <!-- invalid model version to make build fail -->
+  <modelVersion>99.0.0</modelVersion>
+  <groupId>test</groupId>
+  <artifactId>fail-build</artifactId>
+  <version>0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <invalidElementShouldFailBuild/>
+</project>
diff --git a/src/it/fail-build-with-verify-streamLogsOnFailures/verify.groovy b/src/it/fail-build-with-verify-streamLogsOnFailures/verify.groovy
new file mode 100644
index 0000000..7d5bdd1
--- /dev/null
+++ b/src/it/fail-build-with-verify-streamLogsOnFailures/verify.groovy
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+def FS = File.separator
+def buildLogOfProject = new File( basedir, 'target/it/project/build.log' ).text
+
+def buildLog = new File( basedir, 'build.log' ).text
+
+assert buildLog.contains( '*** begin build.log for: project' + FS + 'pom.xml ***' )
+assert buildLog.contains( buildLogOfProject )
+assert buildLog.contains( '*** end build.log for: project' + FS + 'pom.xml ***' )
+
+assert buildLog.contains( 'maven-invoker-plugin:' + projectVersion + ':integration-test' )
+assert buildLog.contains( '[ERROR] Failed to execute goal org.apache.maven.plugins:maven-invoker-plugin:' + projectVersion + ':verify' )
+
diff --git a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
index abcbb96..6a5c879 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
@@ -1659,7 +1659,6 @@ public abstract class AbstractInvokerMojo
         // let's set what details we can
         buildJob.setName( invokerProperties.getJobName() );
         buildJob.setDescription( invokerProperties.getJobDescription() );
-        ExecutionResult executionResult = null;
 
         try
         {
@@ -1668,18 +1667,27 @@ public abstract class AbstractInvokerMojo
             {
                 long milliseconds = System.currentTimeMillis();
                 boolean executed;
+
+                FileLogger buildLogger = setupBuildLogFile( basedir );
+                if ( buildLogger != null )
+                {
+                    buildJob.setBuildlog( buildLogger.getOutputFile().getAbsolutePath() );
+                }
+
                 try
                 {
-                    // CHECKSTYLE_OFF: LineLength
-                    executionResult =
-                        runBuild( basedir, interpolatedPomFile, settingsFile, actualJavaHome, invokerProperties );
-                    // CHECKSTYLE_ON: LineLength
-                    executed = executionResult.executed;
+                    executed = runBuild( basedir, interpolatedPomFile, settingsFile, actualJavaHome,
+                            invokerProperties, buildLogger );
                 }
                 finally
                 {
                     milliseconds = System.currentTimeMillis() - milliseconds;
                     buildJob.setTime( milliseconds / 1000.0 );
+
+                    if ( buildLogger != null )
+                    {
+                        buildLogger.close();
+                    }
                 }
 
                 if ( executed )
@@ -1779,7 +1787,7 @@ public abstract class AbstractInvokerMojo
         finally
         {
             deleteInterpolatedPomFile( interpolatedPomFile );
-            writeBuildReport( buildJob, executionResult );
+            writeBuildReport( buildJob );
         }
     }
 
@@ -1846,7 +1854,7 @@ public abstract class AbstractInvokerMojo
      * @param buildJob The build job whose report should be written, must not be <code>null</code>.
      * @throws org.apache.maven.plugin.MojoExecutionException If the report could not be written.
      */
-    private void writeBuildReport( BuildJob buildJob, ExecutionResult executionResult )
+    private void writeBuildReport( BuildJob buildJob )
         throws MojoExecutionException
     {
         if ( disableReports )
@@ -1875,11 +1883,11 @@ public abstract class AbstractInvokerMojo
 
         if ( writeJunitReport )
         {
-            writeJunitReport( buildJob, safeFileName, executionResult );
+            writeJunitReport( buildJob, safeFileName );
         }
     }
 
-    private void writeJunitReport( BuildJob buildJob, String safeFileName, ExecutionResult executionResult )
+    private void writeJunitReport( BuildJob buildJob, String safeFileName )
         throws MojoExecutionException
     {
         File reportFile = new File( reportsDirectory, "TEST-" + safeFileName + ".xml" );
@@ -1922,23 +1930,26 @@ public abstract class AbstractInvokerMojo
         Xpp3Dom systemOut = new Xpp3Dom( "system-out" );
         testcase.addChild( systemOut );
 
-        if ( executionResult != null && executionResult.fileLogger != null )
+
+        File buildLogFile = buildJob.getBuildlog() != null ? new File( buildJob.getBuildlog() ) : null;
+
+        if ( buildLogFile != null && buildLogFile.exists() )
         {
-            getLog().debug( "fileLogger:" + executionResult.fileLogger.getOutputFile() );
+            getLog().debug( "fileLogger:" + buildLogFile );
             try
             {
-                systemOut.setValue( FileUtils.fileRead( executionResult.fileLogger.getOutputFile() ) );
+                systemOut.setValue( FileUtils.fileRead( buildLogFile ) );
             }
             catch ( IOException e )
             {
-                throw new MojoExecutionException( "Failed to read logfile " + executionResult.fileLogger.getOutputFile()
-                    , e );
+                throw new MojoExecutionException( "Failed to read logfile " + buildLogFile, e );
             }
         }
         else
         {
-            getLog().debug( safeFileName + ", executionResult:" + executionResult );
+            getLog().debug( safeFileName + "not exists buildLogFile = " + buildLogFile );
         }
+
         try ( FileOutputStream fos = new FileOutputStream( reportFile );
               Writer osw = new OutputStreamWriter( fos, buildJob.getModelEncoding() ) )
         {
@@ -1968,14 +1979,15 @@ public abstract class AbstractInvokerMojo
      * @param settingsFile The (already interpolated) user settings file for the build, may be <code>null</code>. Will
      *            be merged with the settings file of the invoking Maven process.
      * @param invokerProperties The properties to use.
+     * @param logger file logger to write execution build.log
      * @return <code>true</code> if the project was launched or <code>false</code> if the selector script indicated that
      *         the project should be skipped.
      * @throws org.apache.maven.plugin.MojoExecutionException If the project could not be launched.
      * @throws org.apache.maven.shared.scriptinterpreter.RunFailureException If either a hook script or the build itself
      *             failed.
      */
-    private ExecutionResult runBuild( File basedir, File pomFile, File settingsFile, File actualJavaHome,
-                              InvokerProperties invokerProperties )
+    private boolean runBuild( File basedir, File pomFile, File settingsFile, File actualJavaHome,
+                                      InvokerProperties invokerProperties, FileLogger logger )
         throws MojoExecutionException, RunFailureException
     {
         if ( getLog().isDebugEnabled() && !invokerProperties.getProperties().isEmpty() )
@@ -1995,9 +2007,8 @@ public abstract class AbstractInvokerMojo
 
         Map<String, Object> context = new LinkedHashMap<>();
 
-        FileLogger logger = setupBuildLogFile( basedir );
         boolean selectorResult = true;
-        ExecutionResult executionResult = new ExecutionResult();
+
         try
         {
             try
@@ -2013,8 +2024,7 @@ public abstract class AbstractInvokerMojo
             catch ( RunFailureException e )
             {
                 selectorResult = false;
-                executionResult.executed = false;
-                return executionResult;
+                return false;
             }
 
             scriptRunner.run( "pre-build script", basedir, preBuildHookScript, context, logger,
@@ -2137,14 +2147,8 @@ public abstract class AbstractInvokerMojo
             {
                 runPostBuildHook( basedir, context, logger );
             }
-            if ( logger != null )
-            {
-                logger.close();
-            }
         }
-        executionResult.executed = true;
-        executionResult. fileLogger = logger;
-        return executionResult;
+        return true;
     }
 
     int getParallelThreadsCount()
@@ -2161,18 +2165,6 @@ public abstract class AbstractInvokerMojo
         }
     }
 
-    private static class ExecutionResult
-    {
-        boolean executed;
-        FileLogger fileLogger;
-
-        @Override
-        public String toString()
-        {
-            return "ExecutionResult{" + "executed=" + executed + ", fileLogger=" + fileLogger + '}';
-        }
-    }
-
     private void runPostBuildHook( File basedir, Map<String, Object> context, FileLogger logger )
         throws MojoExecutionException, RunFailureException
     {
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerMojo.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerMojo.java
index 5459a7e..6dbbbd4 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/InvokerMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerMojo.java
@@ -57,6 +57,14 @@ public class InvokerMojo
     @Parameter( property = "invoker.failIfNoProjects" )
     private Boolean failIfNoProjects;
 
+    /**
+     * Set to <code>true</code> to output build.log to mojo log in case of failed jobs.
+     *
+     * @since 3.2.2
+     */
+    @Parameter( property = "invoker.streamLogsOnFailures", defaultValue = "false" )
+    private boolean streamLogsOnFailures;
+
     void processResults( InvokerSession invokerSession )
         throws MojoFailureException
     {
@@ -65,6 +73,11 @@ public class InvokerMojo
             invokerSession.logSummary( getLog(), ignoreFailures );
         }
 
+        if ( streamLogsOnFailures )
+        {
+            invokerSession.logFailedBuildLog( getLog(), ignoreFailures );
+        }
+
         invokerSession.handleFailures( getLog(), ignoreFailures );
     }
 
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java
index 43ed9bb..1cba4a0 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java
@@ -21,12 +21,16 @@ package org.apache.maven.plugins.invoker;
 
 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
 
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.invoker.model.BuildJob;
 import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.shared.utils.io.IOUtil;
 
 /**
  * Tracks a set of build jobs and their results.
@@ -35,6 +39,8 @@ import org.apache.maven.plugin.logging.Log;
  */
 class InvokerSession
 {
+    private static final String SEPARATOR = buffer().strong(
+            "-------------------------------------------------" ).toString();
 
     private List<BuildJob> buildJobs;
 
@@ -197,43 +203,58 @@ class InvokerSession
     {
         updateStats();
 
-        String separator = buffer().strong( "-------------------------------------------------" ).toString();
-
-        logger.info( separator );
+        logger.info( SEPARATOR );
         logger.info( "Build Summary:" );
-        logger.info( "  Passed: " + successfulJobs.size() + ", Failed: " + failedJobs.size() + ", Errors: "
-            + errorJobs.size() + ", Skipped: " + skippedJobs.size() );
-        logger.info( separator );
+        logger.info( "  Passed: " + successfulJobs.size()
+                + ", Failed: " + failedJobs.size()
+                + ", Errors: " + errorJobs.size()
+                + ", Skipped: " + skippedJobs.size() );
+        logger.info( SEPARATOR );
+
+        logBuildJobList( logger, ignoreFailures, "The following builds failed:", failedJobs );
+        logBuildJobList( logger, ignoreFailures, "The following builds finished with error:", errorJobs );
+        logBuildJobList( logger, ignoreFailures, "The following builds was skipped:", skippedJobs );
+    }
 
-        if ( !failedJobs.isEmpty() )
-        {
-            String heading = "The following builds failed:";
-            if ( ignoreFailures )
-            {
-                logger.warn( heading );
-            }
-            else
-            {
-                logger.error( heading );
-            }
+    public void logFailedBuildLog( Log logger, boolean ignoreFailures )
+            throws MojoFailureException
+    {
+        List<BuildJob> jobToLogs = new ArrayList<>( failedJobs );
+        jobToLogs.addAll( errorJobs );
 
-            for ( BuildJob buildJob : failedJobs )
+        for ( BuildJob buildJob: jobToLogs )
+        {
+            File buildLogFile = buildJob.getBuildlog() != null ? new File( buildJob.getBuildlog() ) : null;
+            if ( buildLogFile != null && buildLogFile.exists() )
             {
-                String item = "*  " + buildJob.getProject();
-                if ( ignoreFailures )
+                try
                 {
-                    logger.warn( item );
+                    // prepare message with build.log in one string to omit begin [ERROR], [WARN]
+                    // so whole log will be displayed without decoration
+                    StringBuilder buildLogMessage = new StringBuilder( );
+                    buildLogMessage.append( System.lineSeparator() );
+                    buildLogMessage.append( System.lineSeparator() );
+                    buildLogMessage.append( "*** begin build.log for: " + buildJob.getProject() + " ***" );
+                    buildLogMessage.append( System.lineSeparator() );
+                    buildLogMessage.append( IOUtil.toString( new FileReader( buildLogFile ) ) );
+                    buildLogMessage.append( "*** end build.log for: " + buildJob.getProject() + " ***" );
+                    buildLogMessage.append( System.lineSeparator() );
+
+                    logWithLevel( logger, ignoreFailures, SEPARATOR );
+                    logWithLevel( logger, ignoreFailures,  buildLogMessage.toString() );
+                    logWithLevel( logger, ignoreFailures, SEPARATOR );
+                    logWithLevel( logger, ignoreFailures, "" );
+
                 }
-                else
+                catch ( IOException e )
                 {
-                    logger.error( item );
+                    throw new MojoFailureException( e.getMessage(), e );
                 }
             }
-
-            logger.info( separator );
         }
     }
 
+
     /**
      * Handles the build failures in this session.
      *
@@ -275,4 +296,47 @@ class InvokerSession
         }
     }
 
+    /**
+     * Log list of jobs.
+     *
+     * @param logger logger to write
+     * @param warn flag indicate log level
+     * @param buildJobs jobs to list
+     */
+    private void logBuildJobList( Log logger, boolean warn, String header, List<BuildJob> buildJobs )
+    {
+        if ( buildJobs.isEmpty() )
+        {
+            return;
+        }
+
+        logWithLevel( logger, warn, header );
+
+        for ( BuildJob buildJob : buildJobs )
+        {
+            logWithLevel( logger, warn, "*  " + buildJob.getProject() );
+        }
+
+        logger.info( SEPARATOR );
+    }
+
+    /**
+     * Log message in correct level depends on flag.
+     *
+     * @param logger logger to write
+     * @param warn flag indicate log level
+     * @param message message to write
+     */
+    private void logWithLevel( Log logger, boolean warn, String message )
+    {
+
+        if ( warn )
+        {
+            logger.warn( message );
+        }
+        else
+        {
+            logger.error( message );
+        }
+    }
 }
diff --git a/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java b/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java
index 5592f3d..bc4abc4 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java
@@ -86,6 +86,14 @@ public class VerifyMojo
     private Boolean failIfNoProjects;
 
     /**
+     * Set to <code>true</code> to output build.log to mojo log in case of failed jobs.
+     *
+     * @since 3.2.2
+     */
+    @Parameter( property = "invoker.streamLogsOnFailures", defaultValue = "false" )
+    private boolean streamLogsOnFailures;
+
+    /**
      * Invokes Maven on the configured test projects.
      *
      * @throws org.apache.maven.plugin.MojoExecutionException If the goal encountered severe errors.
@@ -137,6 +145,11 @@ public class VerifyMojo
             invokerSession.logSummary( getLog(), ignoreFailures );
         }
 
+        if ( streamLogsOnFailures )
+        {
+            invokerSession.logFailedBuildLog( getLog(), ignoreFailures );
+        }
+
         invokerSession.handleFailures( getLog(), ignoreFailures );
     }
 
diff --git a/src/main/mdo/invocation.mdo b/src/main/mdo/invocation.mdo
index ad8b0c4..bc488f4 100644
--- a/src/main/mdo/invocation.mdo
+++ b/src/main/mdo/invocation.mdo
@@ -103,6 +103,13 @@ under the License.
           <type>int</type>
           <description>BuildJobs will be sorted in the descending order of the ordinal. In other words, the BuildJobs with the highest numbers will be executed first</description>
         </field>
+        <field xml.attribute="true">
+          <name>buildlog</name>
+          <version>1.0.0</version>
+          <required>false</required>
+          <type>String</type>
+          <description>The build log filename</description>
+        </field>
       </fields>
       <codeSegments>
         <codeSegment>
diff --git a/src/site/apt/examples/logs-for-failed-tests.apt.vm b/src/site/apt/examples/logs-for-failed-tests.apt.vm
new file mode 100644
index 0000000..57e3f62
--- /dev/null
+++ b/src/site/apt/examples/logs-for-failed-tests.apt.vm
@@ -0,0 +1,56 @@
+ ------
+ Inspect logs for failed tests
+ ------
+ Slawomir Jaranowski
+ ------
+ 2020-05-20
+ ------
+
+ ~~ Licensed to the Apache Software Foundation (ASF) under one
+ ~~ or more contributor license agreements.  See the NOTICE file
+ ~~ distributed with this work for additional information
+ ~~ regarding copyright ownership.  The ASF licenses this file
+ ~~ to you under the Apache License, Version 2.0 (the
+ ~~ "License"); you may not use this file except in compliance
+ ~~ with the License.  You may obtain a copy of the License at
+ ~~
+ ~~   http://www.apache.org/licenses/LICENSE-2.0
+ ~~
+ ~~ Unless required by applicable law or agreed to in writing,
+ ~~ software distributed under the License is distributed on an
+ ~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~~ KIND, either express or implied.  See the License for the
+ ~~ specific language governing permissions and limitations
+ ~~ under the License.
+
+ ~~ NOTE: For help with the syntax of this file, see:
+ ~~ http://maven.apache.org/doxia/references/apt-format.html
+
+Inspect logs for failed tests
+
+  In the usual build all tests pass as we expect,
+  so printing logs from all tests to project build log make our standard build log illegible.
+  The problem begin when some of test was failed,
+  especially when happened on CI system when access to files from build workspace is difficult.
+
+  In order to help investigation on failed test we can use option: <<<streamLogsOnFailures>>>.
+  Now logs from all failed test will be printed to project build log when all test will have finished.
+
++---+
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-invoker-plugin</artifactId>
+        <version>${project.version}</version>
+        <configuration>
+          <streamLogsOnFailures>true</streamLogsOnFailures>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  ...
+</project>
++---+
diff --git a/src/site/site.xml b/src/site/site.xml
index c754d61..5c9f2c2 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -69,6 +69,7 @@ under the License.
       <item name="Fast Build Configuration" href="examples/fast-use.html"/>
       <item name="Installing Artifacts" href="examples/install-artifacts.html"/>
       <item name="Invoker Properties" href="examples/invoker-properties.html"/>
+      <item name="Inspect logs for failed tests" href="examples/logs-for-failed-tests.html"/>
       <item name="Selector Conditions" href="examples/selector-conditions.html"/>
       <item name="Selector Scripts" href="examples/selector-scripts.html"/>
       <item name="Using a Post Build Script" href="examples/post-build-script.html"/>