You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2016/09/16 22:55:06 UTC

[5/5] maven-surefire git commit: [SUREFIRE-1254] add color messages

[SUREFIRE-1254] add color messages


Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/6a79127a
Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/6a79127a
Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/6a79127a

Branch: refs/heads/master
Commit: 6a79127ab63273f0f1f5268c65e4806761871a46
Parents: 2c9edf0
Author: Tibor17 <ti...@lycos.com>
Authored: Fri Sep 16 22:56:10 2016 +0200
Committer: Tibor17 <ti...@lycos.com>
Committed: Sat Sep 17 00:53:49 2016 +0200

----------------------------------------------------------------------
 README.md                                       |   4 +-
 maven-failsafe-plugin/pom.xml                   |   1 -
 .../plugin/failsafe/IntegrationTestMojo.java    |  12 +-
 .../maven/plugin/failsafe/VerifyMojo.java       |  64 +++++--
 maven-surefire-common/pom.xml                   |  46 +++++
 .../plugin/surefire/AbstractSurefireMojo.java   | 149 +++++++++------
 .../maven/plugin/surefire/CommonReflector.java  |  34 ++--
 .../surefire/InPluginVMSurefireStarter.java     |  41 +++--
 .../surefire/StartupReportConfiguration.java    |  18 +-
 .../surefire/SurefireDependencyResolver.java    |   7 +-
 .../maven/plugin/surefire/SurefireHelper.java   |   9 +-
 .../surefire/booterclient/ForkStarter.java      |  39 ++--
 .../surefire/booterclient/ProviderDetector.java | 101 +---------
 .../booterclient/output/ForkClient.java         |  77 +++++---
 .../output/NativeStdErrStreamConsumer.java      |  38 ++++
 .../surefire/log/PluginConsoleLogger.java       | 126 +++++++++++++
 .../plugin/surefire/report/ConsoleReporter.java |  79 ++++----
 .../surefire/report/DefaultReporterFactory.java | 141 ++++++++++----
 .../surefire/report/DirectConsoleOutput.java    |   9 +-
 .../plugin/surefire/report/FileReporter.java    |  37 +---
 .../surefire/report/TestSetRunListener.java     |  80 ++++++--
 .../plugin/surefire/report/TestSetStats.java    | 125 ++++++++++++-
 .../maven/surefire/report/RunStatistics.java    |   4 -
 .../maven/surefire/spi/ServiceLoader.java       | 171 +++++++++++++++++
 .../plugin/surefire/SurefireReflectorTest.java  |   1 +
 .../booterclient/ForkingRunListenerTest.java    |  15 +-
 .../surefire/booterclient/MockReporter.java     |  28 ++-
 .../TestSetMockReporterFactory.java             |   6 +-
 .../report/DefaultReporterFactoryTest.java      |  90 +++++----
 .../apache/maven/surefire/JUnit4SuiteTest.java  |   6 +-
 .../maven/surefire/spi/CustomizedImpl.java      |  33 ++++
 .../apache/maven/surefire/spi/DefaultImpl.java  |  33 ++++
 .../surefire/spi/EmptyServiceInterface.java     |  30 +++
 .../surefire/spi/ExistingServiceInterface.java  |  30 +++
 .../org/apache/maven/surefire/spi/IDefault.java |  33 ++++
 .../maven/surefire/spi/NoServiceInterface.java  |  30 +++
 .../org/apache/maven/surefire/spi/SPITest.java  |  89 +++++++++
 .../org/apache/maven/surefire/spi/SPImpl1.java  |  44 +++++
 .../org/apache/maven/surefire/spi/SPImpl2.java  |  44 +++++
 ...che.maven.surefire.spi.EmptyServiceInterface |  21 +++
 ....maven.surefire.spi.ExistingServiceInterface |  24 +++
 .../org.apache.maven.surefire.spi.IDefault      |  22 +++
 maven-surefire-plugin/pom.xml                   |  26 +++
 .../maven/plugin/surefire/SurefirePlugin.java   |   4 +-
 maven-surefire-plugin/src/site/apt/index.apt.vm |   4 +
 maven-surefire-report-plugin/pom.xml            |  55 ++++++
 .../report/AbstractSurefireReportMojo.java      |  84 +++++----
 .../surefire/report/FailsafeReportMojo.java     |   2 +-
 .../surefire/report/PluginConsoleLogger.java    | 140 ++++++++++++++
 .../report/SurefireReportGenerator.java         |  23 +--
 .../surefire/report/Surefire597Test.java        |   5 +-
 pom.xml                                         |   6 +
 surefire-api/pom.xml                            |   4 +
 .../surefire/booter/BaseProviderFactory.java    |   8 +-
 .../maven/surefire/booter/CommandReader.java    |  24 ++-
 .../surefire/booter/ForkingRunListener.java     |  96 ++++++++--
 .../surefire/booter/SurefireReflector.java      |  23 ++-
 .../providerapi/ProviderParameters.java         |   6 +-
 .../maven/surefire/report/ConsoleLogger.java    |  33 ----
 .../surefire/report/ConsoleOutputCapture.java   |  13 +-
 .../maven/surefire/report/ConsoleStream.java    |   1 +
 .../surefire/report/DefaultConsoleReporter.java |  41 -----
 .../report/DefaultDirectConsoleReporter.java    |  11 +-
 .../maven/surefire/report/MockReporter.java     | 183 -------------------
 .../maven/surefire/booter/ForkedBooter.java     |  54 +++---
 surefire-integration-tests/pom.xml              |  47 +----
 .../surefire/its/Junit47concurrencyIT.java      |   4 +-
 .../maven/surefire/its/Not2xCompatible.java     |  27 ---
 .../surefire/its/fixture/HelperAssertions.java  |   8 +-
 .../Surefire1122ParallelAndFlakyTestsIT.java    |   2 -
 ...urefire1136CwdPropagationInForkedModeIT.java |   3 -
 .../jiras/Surefire1158RemoveInfoLinesIT.java    |   3 -
 ...e735ForkFailWithRedirectConsoleOutputIT.java |   3 -
 .../Surefire806SpecifiedTestControlsIT.java     |   3 -
 .../test/resources/concurrentjunit47/pom.xml    |   7 +-
 .../pom.xml                                     |  13 +-
 .../pom.xml                                     |  13 +-
 .../pom.xml                                     |  11 +-
 surefire-logger-api/pom.xml                     |  54 ++++++
 .../plugin/surefire/log/api/ConsoleLogger.java  |  64 +++++++
 .../log/api/ConsoleLoggerDecorator.java         |   1 +
 .../surefire/log/api/ConsoleLoggerUtils.java    |  55 ++++++
 .../maven/plugin/surefire/log/api/Level.java    |  66 +++++++
 .../surefire/log/api/NullConsoleLogger.java     |  53 ++++++
 .../surefire/log/api/PrintStreamLogger.java     |   1 +
 .../maven/surefire/junit/JUnit3Provider.java    |   1 -
 .../surefire/junit4/JUnit4ProviderTest.java     |   4 +-
 .../junitcore/ClassesParallelRunListener.java   |   7 +-
 .../junitcore/ConcurrentRunListener.java        |  54 +++---
 .../surefire/junitcore/JUnitCoreProvider.java   |  18 +-
 .../surefire/junitcore/JUnitCoreWrapper.java    |  10 +-
 .../junitcore/MethodsParallelRunListener.java   |   7 +-
 .../pc/AbstractThreadPoolStrategy.java          |   6 +-
 .../surefire/junitcore/pc/InvokerStrategy.java  |   4 +-
 .../pc/NonSharedThreadPoolStrategy.java         |   4 +-
 .../junitcore/pc/ParallelComputerBuilder.java   |   8 +-
 .../maven/surefire/junitcore/pc/Scheduler.java  |  34 ++--
 .../junitcore/pc/SchedulingStrategies.java      |  10 +-
 .../junitcore/pc/SchedulingStrategy.java        |   8 +-
 .../junitcore/pc/SharedThreadPoolStrategy.java  |   4 +-
 .../junitcore/pc/SingleThreadScheduler.java     |   6 +-
 .../junitcore/ConcurrentRunListenerTest.java    |   9 +-
 .../junitcore/DefaultConsoleReporter.java       |  68 +++++++
 .../surefire/junitcore/JUnitCoreTester.java     |  14 +-
 .../apache/maven/surefire/junitcore/Logger.java |  30 ---
 .../surefire/junitcore/Surefire746Test.java     |  11 +-
 .../pc/ParallelComputerBuilderTest.java         |  41 +++--
 .../junitcore/pc/ParallelComputerUtilTest.java  |  15 +-
 .../junitcore/pc/SchedulingStrategiesTest.java  |  20 +-
 surefire-report-parser/pom.xml                  |   4 +
 .../surefire/report/SurefireReportParser.java   |  15 +-
 .../surefire/report/TestSuiteXmlParser.java     |  15 +-
 .../report/SurefireReportParserTest.java        |   7 +-
 .../surefire/report/TestSuiteXmlParserTest.java |  69 ++++++-
 .../surefire/its/StagedLocalRepoHelper.java     |   2 +
 115 files changed, 2637 insertions(+), 1143 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index f5e147d..e7b4b07 100644
--- a/README.md
+++ b/README.md
@@ -24,10 +24,8 @@ Usage of [maven-surefire-plugin], [maven-failsafe-plugin], [maven-surefire-repor
 
 # Development Information
 
-Surefire needs Maven 3.0.5 and JDK 1.6+ to be built.
+Surefire needs to use Maven 3.1.0+ and JDK 1.6+ to be built.
 But in order to run IT tests, you can do:
-* -DmavenHomeUsed= path to a Maven 2.x home or -Pmaven-2.2.1, this profile will download Maven 2.2.1 distribution.
-  Use it to run integration tests.
 * In order to run tests for a release check during the vote the following memory requirements are needed:
   $ export MAVEN_OPTS="-Xmx768m -XX:MaxPermSize=1g -XX:SoftRefLRUPolicyMSPerMB=50 -Djava.awt.headless=true"
 * $ mvn install site site:stage -P reporting,run-its

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-failsafe-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/pom.xml b/maven-failsafe-plugin/pom.xml
index 5ca813a..fb1c0b6 100644
--- a/maven-failsafe-plugin/pom.xml
+++ b/maven-failsafe-plugin/pom.xml
@@ -203,7 +203,6 @@
           </execution>
         </executions>
       </plugin>
-
     </plugins>
   </build>
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
index bf50fec..78a3cd7 100644
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
+++ b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/IntegrationTestMojo.java
@@ -34,10 +34,11 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
-import org.apache.maven.shared.utils.ReaderFactory;
 import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.surefire.suite.RunResult;
 
+import static org.apache.maven.shared.utils.ReaderFactory.FILE_ENCODING;
+
 /**
  * Run integration tests using Surefire.
  *
@@ -363,10 +364,11 @@ public class IntegrationTestMojo
     {
         if ( StringUtils.isEmpty( encoding ) )
         {
-            getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
-                           + ", i.e. build is platform dependent! The file encoding for reports output files "
-                               + "should be provided by the POM property ${project.reporting.outputEncoding}." );
-            return ReaderFactory.FILE_ENCODING;
+            getConsoleLogger().warning( "File encoding has not been set, using platform encoding "
+                + FILE_ENCODING
+                + ", i.e. build is platform dependent! The file encoding for reports output files "
+                + "should be provided by the POM property ${project.reporting.outputEncoding}." );
+            return FILE_ENCODING;
         }
         else
         {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
----------------------------------------------------------------------
diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
index 95f522e..37199a3 100644
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
+++ b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
@@ -33,16 +33,21 @@ import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.surefire.SurefireHelper;
 import org.apache.maven.plugin.surefire.SurefireReportParameters;
+import org.apache.maven.plugin.surefire.log.PluginConsoleLogger;
 import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.shared.utils.ReaderFactory;
-import org.apache.maven.shared.utils.StringUtils;
-import org.apache.maven.shared.utils.io.IOUtil;
 import org.apache.maven.surefire.cli.CommandLineOption;
 import org.apache.maven.surefire.suite.RunResult;
 
+import static org.apache.maven.plugin.surefire.SurefireHelper.reportExecution;
+import static org.apache.maven.shared.utils.ReaderFactory.FILE_ENCODING;
+import static org.apache.maven.shared.utils.StringUtils.capitalizeFirstLetter;
+import static org.apache.maven.shared.utils.StringUtils.isEmpty;
+import static org.apache.maven.shared.utils.io.IOUtil.close;
+import static org.apache.maven.surefire.suite.RunResult.noTestsRun;
+
 /**
  * Verify integration tests ran using Surefire.
  *
@@ -159,6 +164,8 @@ public class VerifyMojo
 
     private Collection<CommandLineOption> cli;
 
+    private volatile PluginConsoleLogger consoleLogger;
+
     public void execute()
         throws MojoExecutionException, MojoFailureException
     {
@@ -166,26 +173,28 @@ public class VerifyMojo
         if ( verifyParameters() )
         {
             logDebugOrCliShowErrors(
-                StringUtils.capitalizeFirstLetter( getPluginName() ) + " report directory: " + getReportsDirectory() );
+                capitalizeFirstLetter( getPluginName() ) + " report directory: " + getReportsDirectory() );
 
             RunResult summary;
             try
             {
                 final String encoding;
-                if ( StringUtils.isEmpty( this.encoding ) )
+                if ( isEmpty( this.encoding ) )
                 {
-                    getLog().warn( "File encoding has not been set, using platform encoding "
-                            + ReaderFactory.FILE_ENCODING
-                            + ", i.e. build is platform dependent! The file encoding for reports output files "
-                            + "should be provided by the POM property ${project.reporting.outputEncoding}." );
-                    encoding = ReaderFactory.FILE_ENCODING;
+                    getConsoleLogger()
+                            .warning( "File encoding has not been set, using platform encoding "
+                                              + FILE_ENCODING
+                                              + ", i.e. build is platform dependent! The file encoding for "
+                                              + "reports output files should be provided by the POM property "
+                                              + "${project.reporting.outputEncoding}." );
+                    encoding = FILE_ENCODING;
                 }
                 else
                 {
                     encoding = this.encoding;
                 }
 
-                summary = existsSummaryFile() ? readSummary( encoding, summaryFile ) : RunResult.noTestsRun();
+                summary = existsSummaryFile() ? readSummary( encoding, summaryFile ) : noTestsRun();
 
                 if ( existsSummaryFiles() )
                 {
@@ -200,8 +209,23 @@ public class VerifyMojo
                 throw new MojoExecutionException( e.getMessage(), e );
             }
 
-            SurefireHelper.reportExecution( this, summary, getLog() );
+            reportExecution( this, summary, getConsoleLogger() );
+        }
+    }
+
+    private PluginConsoleLogger getConsoleLogger()
+    {
+        if ( consoleLogger == null )
+        {
+            synchronized ( this )
+            {
+                if ( consoleLogger == null )
+                {
+                    consoleLogger = new PluginConsoleLogger( getLog() );
+                }
+            }
         }
+        return consoleLogger;
     }
 
     private RunResult readSummary( String encoding, File summaryFile )
@@ -219,9 +243,9 @@ public class VerifyMojo
         }
         finally
         {
-            IOUtil.close( reader );
-            IOUtil.close( bufferedInputStream );
-            IOUtil.close( fileInputStream );
+            close( reader );
+            close( bufferedInputStream );
+            close( fileInputStream );
         }
     }
 
@@ -230,7 +254,7 @@ public class VerifyMojo
     {
         if ( isSkip() || isSkipTests() || isSkipITs() || isSkipExec() )
         {
-            getLog().info( "Tests are skipped." );
+            getConsoleLogger().info( "Tests are skipped." );
             return false;
         }
 
@@ -244,7 +268,7 @@ public class VerifyMojo
 
         if ( !existsSummary() )
         {
-            getLog().info( "No tests to run." );
+            getConsoleLogger().info( "No tests to run." );
             return false;
         }
 
@@ -370,12 +394,12 @@ public class VerifyMojo
 
     private Collection<CommandLineOption> commandLineOptions()
     {
-        return SurefireHelper.commandLineOptions( session, getLog() );
+        return SurefireHelper.commandLineOptions( session, getConsoleLogger() );
     }
 
-    private void logDebugOrCliShowErrors( CharSequence s )
+    private void logDebugOrCliShowErrors( String s )
     {
-        SurefireHelper.logDebugOrCliShowErrors( s, getLog(), cli );
+        SurefireHelper.logDebugOrCliShowErrors( s, getConsoleLogger(), cli );
     }
 
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/pom.xml
----------------------------------------------------------------------
diff --git a/maven-surefire-common/pom.xml b/maven-surefire-common/pom.xml
index aef1950..5336982 100644
--- a/maven-surefire-common/pom.xml
+++ b/maven-surefire-common/pom.xml
@@ -106,6 +106,12 @@
       </exclusions>
     </dependency>
     <dependency>
+      <groupId>org.fusesource.jansi</groupId>
+      <artifactId>jansi</artifactId>
+      <version>1.13</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-all</artifactId>
       <version>1.8.4</version>
@@ -116,12 +122,52 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>1.12</version>
+        <executions>
+          <execution>
+            <id>add-source</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-sources</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>shared-logging-generated-sources</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>unpack</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
+              <overWriteIfNewer>false</overWriteIfNewer>
+              <artifact>org.apache.maven.shared:maven-shared-utils:3.1.0:jar:sources</artifact>
+              <includes>org/apache/maven/shared/utils/logging/*.java</includes>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
           <redirectTestOutputToFile>true</redirectTestOutputToFile>
           <includes>
             <include>**/JUnit4SuiteTest.java</include>
           </includes>
+          <classpathDependencyExcludes>
+            <classpathDependencyExclude>org.fusesource.jansi:jansi</classpathDependencyExclude>
+          </classpathDependencyExcludes>
         </configuration>
         <dependencies>
           <dependency>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index eaa01a8..cd27edf 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -57,11 +57,11 @@ import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugin.surefire.booterclient.ChecksumCalculator;
 import org.apache.maven.plugin.surefire.booterclient.ForkConfiguration;
 import org.apache.maven.plugin.surefire.booterclient.ForkStarter;
 import org.apache.maven.plugin.surefire.booterclient.ProviderDetector;
+import org.apache.maven.plugin.surefire.log.PluginConsoleLogger;
 import org.apache.maven.plugin.surefire.util.DependencyScanner;
 import org.apache.maven.plugin.surefire.util.DirectoryScanner;
 import org.apache.maven.plugins.annotations.Component;
@@ -82,6 +82,7 @@ import org.apache.maven.surefire.booter.SurefireBooterForkException;
 import org.apache.maven.surefire.booter.SurefireExecutionException;
 import org.apache.maven.surefire.cli.CommandLineOption;
 import org.apache.maven.surefire.providerapi.SurefireProvider;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.surefire.report.ReporterConfiguration;
 import org.apache.maven.surefire.suite.RunResult;
 import org.apache.maven.surefire.testset.DirectoryScannerParameters;
@@ -97,6 +98,10 @@ import org.apache.maven.toolchain.ToolchainManager;
 
 import javax.annotation.Nonnull;
 
+import static java.lang.Thread.currentThread;
+import static org.apache.maven.shared.utils.StringUtils.capitalizeFirstLetter;
+import static org.apache.maven.shared.utils.StringUtils.isNotBlank;
+
 /**
  * Abstract base class for running tests using Surefire.
  *
@@ -107,8 +112,7 @@ public abstract class AbstractSurefireMojo
     extends AbstractMojo
     implements SurefireExecutionParameters
 {
-
-    // common mojo parameters
+    private final ProviderDetector providerDetector = new ProviderDetector();
 
     /**
      * Information about this plugin, mainly used to lookup this plugin's configuration from the currently executing
@@ -735,6 +739,8 @@ public abstract class AbstractSurefireMojo
 
     private List<CommandLineOption> cli;
 
+    private volatile PluginConsoleLogger consoleLogger;
+
     public void execute()
         throws MojoExecutionException, MojoFailureException
     {
@@ -760,6 +766,21 @@ public abstract class AbstractSurefireMojo
         }
     }
 
+    protected final PluginConsoleLogger getConsoleLogger()
+    {
+        if ( consoleLogger == null )
+        {
+            synchronized ( this )
+            {
+                if ( consoleLogger == null )
+                {
+                    consoleLogger = new PluginConsoleLogger( getLog() );
+                }
+            }
+        }
+        return consoleLogger;
+    }
+
     private void setupStuff()
     {
         createDependencyResolver();
@@ -812,17 +833,17 @@ public abstract class AbstractSurefireMojo
         setProperties( new SurefireProperties( getProperties() ) );
         if ( isSkipExecution() )
         {
-            getLog().info( "Tests are skipped." );
+            getConsoleLogger().info( "Tests are skipped." );
             return false;
         }
 
         String jvmToUse = getJvm();
         if ( toolchain != null )
         {
-            getLog().info( "Toolchain in maven-" + getPluginName() + "-plugin: " + toolchain );
+            getConsoleLogger().info( "Toolchain in maven-" + getPluginName() + "-plugin: " + toolchain );
             if ( jvmToUse != null )
             {
-                getLog().warn( "Toolchains are ignored, 'executable' parameter is set to " + jvmToUse );
+                getConsoleLogger().warning( "Toolchains are ignored, 'executable' parameter is set to " + jvmToUse );
             }
         }
 
@@ -833,7 +854,7 @@ public abstract class AbstractSurefireMojo
             {
                 throw new MojoFailureException( "No tests to run!" );
             }
-            getLog().info( "No tests to run." );
+            getConsoleLogger().info( "No tests to run." );
         }
         else
         {
@@ -898,9 +919,10 @@ public abstract class AbstractSurefireMojo
 
     private void createDependencyResolver()
     {
-        dependencyResolver =
-            new SurefireDependencyResolver( getArtifactResolver(), getArtifactFactory(), getLog(), getLocalRepository(),
-                                            getRemoteRepositories(), getMetadataSource(), getPluginName() );
+        dependencyResolver = new SurefireDependencyResolver( getArtifactResolver(), getArtifactFactory(),
+                                                                   getConsoleLogger(), getLocalRepository(),
+                                                                   getRemoteRepositories(), getMetadataSource(),
+                                                                   getPluginName() );
     }
 
     protected List<ProviderInfo> createProviders()
@@ -925,13 +947,13 @@ public abstract class AbstractSurefireMojo
         catch ( IOException e )
         {
             String msg = "The system property file '" + systemPropertiesFile.getAbsolutePath() + "' can't be read.";
-            if ( getLog().isDebugEnabled() )
+            if ( getConsoleLogger().isDebugEnabled() )
             {
-                getLog().warn( msg, e );
+                getConsoleLogger().debug( msg, e );
             }
             else
             {
-                getLog().warn( msg );
+                getConsoleLogger().warning( msg );
             }
         }
 
@@ -948,20 +970,25 @@ public abstract class AbstractSurefireMojo
             {
                 if ( getArgLine() == null || !getArgLine().contains( "-D" + o + "=" ) )
                 {
-                    getLog().warn( o + " cannot be set as system property, use <argLine>-D"
-                                       + o + "=...</argLine> instead" );
+                    getConsoleLogger().warning( o + " cannot be set as system property, use <argLine>-D"
+                                                        + o + "=...</argLine> instead"
+                    );
                 }
             }
             for ( Object systemPropertyMatchingArgLine : systemPropertiesMatchingArgLine( result ) )
             {
-                getLog().warn( "The system property " + systemPropertyMatchingArgLine + " is configured twice! "
-                                   + "The property appears in <argLine/> and any of <systemPropertyVariables/>, "
-                                   + "<systemProperties/> or user property." );
+                getConsoleLogger()
+                        .warning( "The system property "
+                                          + systemPropertyMatchingArgLine
+                                          + " is configured twice! "
+                                          + "The property appears in <argLine/> and any of <systemPropertyVariables/>, "
+                                          + "<systemProperties/> or user property."
+                        );
             }
         }
-        if ( getLog().isDebugEnabled() )
+        if ( getConsoleLogger().isDebugEnabled() )
         {
-            showToLog( result, getLog(), "system property" );
+            showToLog( result, getConsoleLogger(), "system property" );
         }
         return result;
     }
@@ -969,7 +996,7 @@ public abstract class AbstractSurefireMojo
     private Set<Object> systemPropertiesMatchingArgLine( SurefireProperties result )
     {
         Set<Object> intersection = new HashSet<Object>();
-        if ( StringUtils.isNotBlank( getArgLine() ) )
+        if ( isNotBlank( getArgLine() ) )
         {
             for ( Object systemProperty : result.getStringKeySet() )
             {
@@ -985,7 +1012,7 @@ public abstract class AbstractSurefireMojo
         return intersection;
     }
 
-    public void showToLog( SurefireProperties props, org.apache.maven.plugin.logging.Log log, String setting )
+    private void showToLog( SurefireProperties props, ConsoleLogger log, String setting )
     {
         for ( Object key : props.getStringKeySet() )
         {
@@ -994,7 +1021,6 @@ public abstract class AbstractSurefireMojo
         }
     }
 
-
     private RunResult executeProvider( ProviderInfo provider, DefaultScanResult scanResult )
         throws MojoExecutionException, MojoFailureException, SurefireExecutionException, SurefireBooterForkException,
         TestSetFailedException
@@ -1016,7 +1042,7 @@ public abstract class AbstractSurefireMojo
         else
         {
             ForkConfiguration forkConfiguration = getForkConfiguration();
-            if ( getLog().isDebugEnabled() )
+            if ( getConsoleLogger().isDebugEnabled() )
             {
                 showMap( getEnvironmentVariables(), "environment variable" );
             }
@@ -1026,7 +1052,7 @@ public abstract class AbstractSurefireMojo
             {
                 ForkStarter forkStarter =
                     createForkStarter( provider, forkConfiguration, classLoaderConfiguration, runOrderParameters,
-                                       getLog() );
+                                       getConsoleLogger() );
                 return forkStarter.run( effectiveProperties, scanResult );
             }
             finally
@@ -1058,16 +1084,17 @@ public abstract class AbstractSurefireMojo
 
     protected void cleanupForkConfiguration( ForkConfiguration forkConfiguration )
     {
-        if ( !getLog().isDebugEnabled() && forkConfiguration != null )
+        if ( !getConsoleLogger().isDebugEnabled() && forkConfiguration != null )
         {
             File tempDirectory = forkConfiguration.getTempDirectory();
             try
             {
                 FileUtils.deleteDirectory( tempDirectory );
             }
-            catch ( IOException ioe )
+            catch ( IOException e )
             {
-                getLog().warn( "Could not delete temp directory " + tempDirectory + " because " + ioe.getMessage() );
+                getConsoleLogger()
+                        .warning( "Could not delete temp directory " + tempDirectory + " because " + e.getMessage() );
             }
         }
     }
@@ -1075,7 +1102,7 @@ public abstract class AbstractSurefireMojo
     protected void logReportsDirectory()
     {
         logDebugOrCliShowErrors(
-            StringUtils.capitalizeFirstLetter( getPluginName() ) + " report directory: " + getReportsDirectory() );
+            capitalizeFirstLetter( getPluginName() ) + " report directory: " + getReportsDirectory() );
     }
 
     final Toolchain getToolchain()
@@ -1121,11 +1148,13 @@ public abstract class AbstractSurefireMojo
         {
             DefaultArtifactVersion defaultArtifactVersion = new DefaultArtifactVersion( testNgArtifact.getVersion() );
             getProperties().setProperty( "testng.configurator", getConfiguratorName( defaultArtifactVersion,
-                                                                                     getLog() ) );
+                                                                                           getConsoleLogger()
+                    )
+            );
         }
     }
 
-    private static String getConfiguratorName( ArtifactVersion version, Log log )
+    private static String getConfiguratorName( ArtifactVersion version, PluginConsoleLogger log )
         throws MojoExecutionException
     {
         try
@@ -1158,7 +1187,7 @@ public abstract class AbstractSurefireMojo
             range = VersionRange.createFromVersionSpec( "[5.14.1,5.14.3)" );
             if ( range.containsVersion( version ) )
             {
-                log.warn( "The 'reporter' or 'listener' may not work properly in TestNG 5.14.1 and 5.14.2." );
+                log.warning( "The 'reporter' or 'listener' may not work properly in TestNG 5.14.1 and 5.14.2." );
                 return "org.apache.maven.surefire.testng.conf.TestNG5141Configurator";
             }
             range = VersionRange.createFromVersionSpec( "[5.14.3,6.0)" );
@@ -1559,11 +1588,11 @@ public abstract class AbstractSurefireMojo
 
             final Classpath testClasspath = generateTestClasspath();
 
-            getLog().debug( testClasspath.getLogMessage( "test" ) );
-            getLog().debug( providerClasspath.getLogMessage( "provider" ) );
+            getConsoleLogger().debug( testClasspath.getLogMessage( "test" ) );
+            getConsoleLogger().debug( providerClasspath.getLogMessage( "provider" ) );
 
-            getLog().debug( testClasspath.getCompactLogMessage( "test(compact)" ) );
-            getLog().debug( providerClasspath.getCompactLogMessage( "provider(compact)" ) );
+            getConsoleLogger().debug( testClasspath.getCompactLogMessage( "test(compact)" ) );
+            getConsoleLogger().debug( providerClasspath.getCompactLogMessage( "provider(compact)" ) );
 
             final ClasspathConfiguration classpathConfiguration =
                 new ClasspathConfiguration( testClasspath, providerClasspath, inprocClassPath,
@@ -1607,12 +1636,12 @@ public abstract class AbstractSurefireMojo
 
     private boolean isSpecificTestSpecified()
     {
-        return StringUtils.isNotBlank( getTest() );
+        return isNotBlank( getTest() );
     }
 
     @Nonnull private List<String> readListFromFile( @Nonnull final File file )
     {
-        getLog().debug( "Reading list from: " + file );
+        getConsoleLogger().debug( "Reading list from: " + file );
 
         if ( !file.exists() )
         {
@@ -1623,12 +1652,12 @@ public abstract class AbstractSurefireMojo
         {
             List<String> list = FileUtils.loadFile( file );
 
-            if ( getLog().isDebugEnabled() )
+            if ( getConsoleLogger().isDebugEnabled() )
             {
-                getLog().debug( "List contents:" );
+                getConsoleLogger().debug( "List contents:" );
                 for ( String entry : list )
                 {
-                    getLog().debug( "  " + entry );
+                    getConsoleLogger().debug( "  " + entry );
                 }
             }
             return list;
@@ -1830,7 +1859,7 @@ public abstract class AbstractSurefireMojo
 
     private ForkStarter createForkStarter( ProviderInfo provider, ForkConfiguration forkConfiguration,
                                              ClassLoaderConfiguration classLoaderConfiguration,
-                                             RunOrderParameters runOrderParameters, Log log )
+                                             RunOrderParameters runOrderParameters, ConsoleLogger log )
         throws MojoExecutionException, MojoFailureException
     {
         StartupConfiguration startupConfiguration = createStartupConfiguration( provider, classLoaderConfiguration );
@@ -1850,7 +1879,8 @@ public abstract class AbstractSurefireMojo
         String configChecksum = getConfigChecksum();
         StartupReportConfiguration startupReportConfiguration = getStartupReportConfiguration( configChecksum );
         ProviderConfiguration providerConfiguration = createProviderConfiguration( runOrderParameters );
-        return new InPluginVMSurefireStarter( startupConfiguration, providerConfiguration, startupReportConfiguration );
+        return new InPluginVMSurefireStarter( startupConfiguration, providerConfiguration,
+                                                    startupReportConfiguration, consoleLogger );
 
     }
 
@@ -1869,7 +1899,7 @@ public abstract class AbstractSurefireMojo
                                       getEffectiveJvm(),
                                       getWorkingDirectory() != null ? getWorkingDirectory() : getBasedir(),
                                       getProject().getModel().getProperties(),
-                                      getArgLine(), getEnvironmentVariables(), getLog().isDebugEnabled(),
+                                      getArgLine(), getEnvironmentVariables(), getConsoleLogger().isDebugEnabled(),
                                       getEffectiveForkCount(), reuseForks );
     }
 
@@ -1893,8 +1923,8 @@ public abstract class AbstractSurefireMojo
 
         if ( !ForkConfiguration.FORK_ONCE.equals( getForkMode() ) )
         {
-            getLog().warn(
-                "The parameter forkMode is deprecated since version 2.14. Use forkCount and reuseForks instead." );
+            getConsoleLogger().warning( "The parameter forkMode is deprecated since version 2.14. "
+                                                + "Use forkCount and reuseForks instead." );
         }
     }
 
@@ -1958,7 +1988,7 @@ public abstract class AbstractSurefireMojo
         {
             // use the same JVM as the one used to run Maven (the "java.home" one)
             jvmToUse = System.getProperty( "java.home" ) + File.separator + "bin" + File.separator + "java";
-            getLog().debug( "Using JVM: " + jvmToUse );
+            getConsoleLogger().debug( "Using JVM: " + jvmToUse );
         }
 
         return jvmToUse;
@@ -2073,7 +2103,8 @@ public abstract class AbstractSurefireMojo
         @SuppressWarnings( "unchecked" ) Map<String, String> pluginContext = getPluginContext();
         if ( pluginContext.containsKey( configChecksum ) )
         {
-            getLog().info( "Skipping execution of surefire because it has already been run for this configuration" );
+            getConsoleLogger()
+                    .info( "Skipping execution of surefire because it has already been run for this configuration" );
             return true;
         }
         pluginContext.put( configChecksum, configChecksum );
@@ -2208,7 +2239,7 @@ public abstract class AbstractSurefireMojo
         {
             String key = (String) o;
             String value = (String) map.get( key );
-            getLog().debug( "Setting " + setting + " [" + key + "]=[" + value + "]" );
+            getConsoleLogger().debug( "Setting " + setting + " [" + key + "]=[" + value + "]" );
         }
     }
 
@@ -2252,7 +2283,7 @@ public abstract class AbstractSurefireMojo
             {
                 Artifact artifact = (Artifact) o;
 
-                getLog().debug(
+                getConsoleLogger().debug(
                     "Adding to " + getPluginName() + " booter test classpath: " + artifact.getFile().getAbsolutePath()
                     + " Scope: " + artifact.getScope() );
 
@@ -2277,13 +2308,13 @@ public abstract class AbstractSurefireMojo
         {
             String msg = "Build uses Maven 2.0.x, cannot propagate system properties"
                 + " from command line to tests (cf. SUREFIRE-121)";
-            if ( getLog().isDebugEnabled() )
+            if ( getConsoleLogger().isDebugEnabled() )
             {
-                getLog().warn( msg, e );
+                getConsoleLogger().debug( msg, e );
             }
             else
             {
-                getLog().warn( msg );
+                getConsoleLogger().warning( msg );
             }
         }
         if ( props == null )
@@ -2346,7 +2377,7 @@ public abstract class AbstractSurefireMojo
     {
         if ( isUseSystemClassLoader() && isNotForking() )
         {
-            getLog().warn( "useSystemClassloader setting has no effect when not forking" );
+            getConsoleLogger().warning( "useSystemClassloader setting has no effect when not forking" );
         }
     }
 
@@ -2357,7 +2388,7 @@ public abstract class AbstractSurefireMojo
 
     private List<CommandLineOption> commandLineOptions()
     {
-        return SurefireHelper.commandLineOptions( getSession(), getLog() );
+        return SurefireHelper.commandLineOptions( getSession(), getConsoleLogger() );
     }
 
     private void warnIfDefunctGroupsCombinations()
@@ -2695,8 +2726,8 @@ public abstract class AbstractSurefireMojo
         {
             try
             {
-                return ProviderDetector.getServiceNames( SurefireProvider.class,
-                                                         Thread.currentThread().getContextClassLoader() );
+                ClassLoader cl = currentThread().getContextClassLoader();
+                return providerDetector.lookupServiceNames( SurefireProvider.class, cl );
             }
             catch ( IOException e )
             {
@@ -3236,8 +3267,8 @@ public abstract class AbstractSurefireMojo
         this.classpathDependencyScopeExclude = classpathDependencyScopeExclude;
     }
 
-    protected void logDebugOrCliShowErrors( CharSequence s )
+    protected void logDebugOrCliShowErrors( String s )
     {
-        SurefireHelper.logDebugOrCliShowErrors( s, getLog(), cli );
+        SurefireHelper.logDebugOrCliShowErrors( s, getConsoleLogger(), cli );
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/CommonReflector.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/CommonReflector.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/CommonReflector.java
index 06ec9a5..4ae589f 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/CommonReflector.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/CommonReflector.java
@@ -21,19 +21,25 @@ package org.apache.maven.plugin.surefire;
 
 import java.io.File;
 import java.lang.reflect.Constructor;
+
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
-import org.apache.maven.surefire.util.ReflectionUtils;
+import org.apache.maven.surefire.booter.SurefireReflector;
 import org.apache.maven.surefire.util.SurefireReflectionException;
 
 import javax.annotation.Nonnull;
 
+import static org.apache.maven.surefire.util.ReflectionUtils.getConstructor;
+import static org.apache.maven.surefire.util.ReflectionUtils.instantiateObject;
+import static org.apache.maven.surefire.util.ReflectionUtils.newInstance;
+
 /**
  * @author Kristian Rosenvold
  */
 public class CommonReflector
 {
     private final Class<?> startupReportConfiguration;
-
+    private final Class<?> consoleLogger;
     private final ClassLoader surefireClassLoader;
 
     public CommonReflector( @Nonnull ClassLoader surefireClassLoader )
@@ -43,6 +49,7 @@ public class CommonReflector
         try
         {
             startupReportConfiguration = surefireClassLoader.loadClass( StartupReportConfiguration.class.getName() );
+            consoleLogger = surefireClassLoader.loadClass( ConsoleLogger.class.getName() );
         }
         catch ( ClassNotFoundException e )
         {
@@ -50,23 +57,22 @@ public class CommonReflector
         }
     }
 
-    public Object createReportingReporterFactory( @Nonnull StartupReportConfiguration startupReportConfiguration )
+    public Object createReportingReporterFactory( @Nonnull StartupReportConfiguration startupReportConfiguration,
+                                                  @Nonnull ConsoleLogger consoleLogger )
     {
-        Class<?>[] args = new Class[]{ this.startupReportConfiguration };
+        Class<?>[] args = { this.startupReportConfiguration, this.consoleLogger };
         Object src = createStartupReportConfiguration( startupReportConfiguration );
-        Object[] params = new Object[]{ src };
-        return ReflectionUtils.instantiateObject( DefaultReporterFactory.class.getName(), args, params,
-                                                  surefireClassLoader );
+        Object logger = SurefireReflector.createConsoleLogger( consoleLogger, surefireClassLoader );
+        Object[] params = { src, logger };
+        return instantiateObject( DefaultReporterFactory.class.getName(), args, params, surefireClassLoader );
     }
 
     private Object createStartupReportConfiguration( @Nonnull StartupReportConfiguration reporterConfiguration )
     {
-        Constructor<?> constructor = ReflectionUtils.getConstructor( startupReportConfiguration,
-                                                                     boolean.class, boolean.class,
-                                                                     String.class, boolean.class, boolean.class,
-                                                                     File.class, boolean.class, String.class,
-                                                                     String.class, boolean.class, int.class,
-                                                                     String.class );
+        Constructor<?> constructor = getConstructor( startupReportConfiguration, boolean.class, boolean.class,
+                                                           String.class, boolean.class, boolean.class, File.class,
+                                                           boolean.class, String.class, String.class, boolean.class,
+                                                           int.class, String.class );
         //noinspection BooleanConstructorCall
         Object[] params = { reporterConfiguration.isUseFile(), reporterConfiguration.isPrintSummary(),
             reporterConfiguration.getReportFormat(), reporterConfiguration.isRedirectTestOutputToFile(),
@@ -74,7 +80,7 @@ public class CommonReflector
             reporterConfiguration.isTrimStackTrace(), reporterConfiguration.getReportNameSuffix(),
             reporterConfiguration.getConfigurationHash(), reporterConfiguration.isRequiresRunHistory(),
             reporterConfiguration.getRerunFailingTestsCount(), reporterConfiguration.getXsdSchemaLocation() };
-        return ReflectionUtils.newInstance( constructor, params );
+        return newInstance( constructor, params );
     }
 
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/InPluginVMSurefireStarter.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/InPluginVMSurefireStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/InPluginVMSurefireStarter.java
index 5ab361d..f0d299e 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/InPluginVMSurefireStarter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/InPluginVMSurefireStarter.java
@@ -19,8 +19,8 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.surefire.booter.ProviderConfiguration;
-import org.apache.maven.surefire.booter.ProviderFactory;
 import org.apache.maven.surefire.booter.StartupConfiguration;
 import org.apache.maven.surefire.booter.SurefireExecutionException;
 import org.apache.maven.surefire.suite.RunResult;
@@ -31,6 +31,8 @@ import javax.annotation.Nonnull;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Map;
 
+import static org.apache.maven.surefire.booter.ProviderFactory.invokeProvider;
+
 /**
  * Starts the provider in the same VM as the surefire plugin.
  * <p/>
@@ -45,20 +47,20 @@ import java.util.Map;
  */
 public class InPluginVMSurefireStarter
 {
+    private final StartupConfiguration startupConfig;
+    private final StartupReportConfiguration startupReportConfig;
+    private final ProviderConfiguration providerConfig;
+    private final ConsoleLogger consoleLogger;
 
-    private final StartupConfiguration startupConfiguration;
-
-    private final StartupReportConfiguration startupReportConfiguration;
-
-    private final ProviderConfiguration providerConfiguration;
-
-    public InPluginVMSurefireStarter( @Nonnull StartupConfiguration startupConfiguration,
-                                      @Nonnull ProviderConfiguration providerConfiguration,
-                                      @Nonnull StartupReportConfiguration startupReportConfiguration )
+    public InPluginVMSurefireStarter( @Nonnull StartupConfiguration startupConfig,
+                                      @Nonnull ProviderConfiguration providerConfig,
+                                      @Nonnull StartupReportConfiguration startupReportConfig,
+                                      @Nonnull ConsoleLogger consoleLogger )
     {
-        this.startupConfiguration = startupConfiguration;
-        this.startupReportConfiguration = startupReportConfiguration;
-        this.providerConfiguration = providerConfiguration;
+        this.startupConfig = startupConfig;
+        this.startupReportConfig = startupReportConfig;
+        this.providerConfig = providerConfig;
+        this.consoleLogger = consoleLogger;
     }
 
     public RunResult runSuitesInProcess( @Nonnull DefaultScanResult scanResult )
@@ -67,20 +69,19 @@ public class InPluginVMSurefireStarter
         // The test classloader must be constructed first to avoid issues with commons-logging until we properly
         // separate the TestNG classloader
 
-        Map<String, String> providerProperties = providerConfiguration.getProviderProperties();
+        Map<String, String> providerProperties = providerConfig.getProviderProperties();
         scanResult.writeTo( providerProperties );
 
-        startupConfiguration.writeSurefireTestClasspathProperty();
-        ClassLoader testsClassLoader = startupConfiguration.getClasspathConfiguration().createMergedClassLoader();
+        startupConfig.writeSurefireTestClasspathProperty();
+        ClassLoader testClassLoader = startupConfig.getClasspathConfiguration().createMergedClassLoader();
 
-        CommonReflector surefireReflector = new CommonReflector( testsClassLoader );
+        CommonReflector surefireReflector = new CommonReflector( testClassLoader );
 
-        final Object factory = surefireReflector.createReportingReporterFactory( startupReportConfiguration );
+        Object factory = surefireReflector.createReportingReporterFactory( startupReportConfig, consoleLogger );
 
         try
         {
-            return ProviderFactory.invokeProvider( null, testsClassLoader, factory,
-                                                   providerConfiguration, false, startupConfiguration, true );
+            return invokeProvider( null, testClassLoader, factory, providerConfig, false, startupConfig, true );
         }
         catch ( InvocationTargetException e )
         {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
index f45b303..30156f9 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/StartupReportConfiguration.java
@@ -27,7 +27,6 @@ import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.maven.plugin.surefire.report.ConsoleOutputFileReporter;
-import org.apache.maven.plugin.surefire.report.ConsoleReporter;
 import org.apache.maven.plugin.surefire.report.DirectConsoleOutput;
 import org.apache.maven.plugin.surefire.report.FileReporter;
 import org.apache.maven.plugin.surefire.report.StatelessXmlReporter;
@@ -37,6 +36,9 @@ import org.apache.maven.plugin.surefire.runorder.StatisticsReporter;
 
 import javax.annotation.Nonnull;
 
+import static org.apache.maven.plugin.surefire.report.ConsoleReporter.BRIEF;
+import static org.apache.maven.plugin.surefire.report.ConsoleReporter.PLAIN;
+
 /**
  * All the parameters used to construct reporters
  * <p/>
@@ -45,9 +47,9 @@ import javax.annotation.Nonnull;
  */
 public class StartupReportConfiguration
 {
-    public static final String BRIEF_REPORT_FORMAT = ConsoleReporter.BRIEF;
+    public static final String BRIEF_REPORT_FORMAT = BRIEF;
 
-    public static final String PLAIN_REPORT_FORMAT = ConsoleReporter.PLAIN;
+    public static final String PLAIN_REPORT_FORMAT = PLAIN;
 
     private final PrintStream originalSystemOut;
 
@@ -186,16 +188,6 @@ public class StartupReportConfiguration
         return BRIEF_REPORT_FORMAT.equals( fmt ) || PLAIN_REPORT_FORMAT.equals( fmt );
     }
 
-    public ConsoleReporter instantiateConsoleReporter()
-    {
-        return shouldReportToConsole() ? new ConsoleReporter( originalSystemOut ) : null;
-    }
-
-    private boolean shouldReportToConsole()
-    {
-        return isUseFile() ? isPrintSummary() : isRedirectTestOutputToFile() || isBriefOrPlainFormat();
-    }
-
     public TestcycleConsoleOutputReceiver instantiateConsoleOutputFileReporter()
     {
         return isRedirectTestOutputToFile()

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireDependencyResolver.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireDependencyResolver.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireDependencyResolver.java
index 41b6171..12a1239 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireDependencyResolver.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireDependencyResolver.java
@@ -37,8 +37,8 @@ import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
 import org.apache.maven.artifact.versioning.VersionRange;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.surefire.booter.Classpath;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -56,7 +56,7 @@ public class SurefireDependencyResolver
 
     private final ArtifactFactory artifactFactory;
 
-    private final org.apache.maven.plugin.logging.Log log;
+    private final ConsoleLogger log;
 
     private final ArtifactRepository localRepository;
 
@@ -66,7 +66,8 @@ public class SurefireDependencyResolver
 
     private final String pluginName;
 
-    protected SurefireDependencyResolver( ArtifactResolver artifactResolver, ArtifactFactory artifactFactory, Log log,
+    protected SurefireDependencyResolver( ArtifactResolver artifactResolver, ArtifactFactory artifactFactory,
+                                          ConsoleLogger log,
                                           ArtifactRepository localRepository,
                                           List<ArtifactRepository> remoteRepositories,
                                           ArtifactMetadataSource artifactMetadataSource, String pluginName )

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireHelper.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireHelper.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireHelper.java
index 8952787..3f87c3c 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireHelper.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/SurefireHelper.java
@@ -23,7 +23,7 @@ import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugin.surefire.log.PluginConsoleLogger;
 import org.apache.maven.surefire.cli.CommandLineOption;
 import org.apache.maven.surefire.suite.RunResult;
 
@@ -54,7 +54,8 @@ public final class SurefireHelper
         throw new IllegalAccessError( "Utility class" );
     }
 
-    public static void reportExecution( SurefireReportParameters reportParameters, RunResult result, Log log )
+    public static void reportExecution( SurefireReportParameters reportParameters, RunResult result,
+                                        PluginConsoleLogger log )
         throws MojoFailureException, MojoExecutionException
     {
         boolean timeoutOrOtherFailure = result.isFailureOrTimeout();
@@ -99,7 +100,7 @@ public final class SurefireHelper
         }
     }
 
-    public static List<CommandLineOption> commandLineOptions( MavenSession session, Log log )
+    public static List<CommandLineOption> commandLineOptions( MavenSession session, PluginConsoleLogger log )
     {
         List<CommandLineOption> cli = new ArrayList<CommandLineOption>();
         if ( log.isErrorEnabled() )
@@ -146,7 +147,7 @@ public final class SurefireHelper
         return unmodifiableList( cli );
     }
 
-    public static void logDebugOrCliShowErrors( CharSequence s, Log log, Collection<CommandLineOption> cli )
+    public static void logDebugOrCliShowErrors( String s, PluginConsoleLogger log, Collection<CommandLineOption> cli )
     {
         if ( cli.contains( LOGGING_LEVEL_DEBUG ) )
         {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
index 2a70927..4f9c813 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
@@ -19,7 +19,6 @@ package org.apache.maven.plugin.surefire.booterclient;
  * under the License.
  */
 
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.plugin.surefire.CommonReflector;
 import org.apache.maven.plugin.surefire.StartupReportConfiguration;
 import org.apache.maven.plugin.surefire.SurefireProperties;
@@ -29,6 +28,7 @@ import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStre
 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream;
 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStream;
 import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
+import org.apache.maven.plugin.surefire.booterclient.output.NativeStdErrStreamConsumer;
 import org.apache.maven.plugin.surefire.booterclient.output.ThreadedStreamConsumer;
 import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
 import org.apache.maven.shared.utils.cli.CommandLineCallable;
@@ -44,6 +44,7 @@ import org.apache.maven.surefire.booter.StartupConfiguration;
 import org.apache.maven.surefire.booter.SurefireBooterForkException;
 import org.apache.maven.surefire.booter.SurefireExecutionException;
 import org.apache.maven.surefire.providerapi.SurefireProvider;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.surefire.report.StackTraceWriter;
 import org.apache.maven.surefire.suite.RunResult;
 import org.apache.maven.surefire.testset.TestRequest;
@@ -141,7 +142,7 @@ public class ForkStarter
 
     private final StartupReportConfiguration startupReportConfiguration;
 
-    private final Log log;
+    private final ConsoleLogger log;
 
     private final DefaultReporterFactory defaultReporterFactory;
 
@@ -200,7 +201,7 @@ public class ForkStarter
 
     public ForkStarter( ProviderConfiguration providerConfiguration, StartupConfiguration startupConfiguration,
                         ForkConfiguration forkConfiguration, int forkedProcessTimeoutInSeconds,
-                        StartupReportConfiguration startupReportConfiguration, Log log )
+                        StartupReportConfiguration startupReportConfiguration, ConsoleLogger log )
     {
         this.forkConfiguration = forkConfiguration;
         this.providerConfiguration = providerConfiguration;
@@ -208,7 +209,7 @@ public class ForkStarter
         this.startupConfiguration = startupConfiguration;
         this.startupReportConfiguration = startupReportConfiguration;
         this.log = log;
-        defaultReporterFactory = new DefaultReporterFactory( startupReportConfiguration );
+        defaultReporterFactory = new DefaultReporterFactory( startupReportConfiguration, log );
         defaultReporterFactory.runStarting();
         defaultReporterFactories = new ConcurrentLinkedQueue<DefaultReporterFactory>();
         currentForkClients = new ConcurrentLinkedQueue<ForkClient>();
@@ -239,13 +240,13 @@ public class ForkStarter
     private RunResult run( SurefireProperties effectiveSystemProperties, Map<String, String> providerProperties )
             throws SurefireBooterForkException
     {
-        DefaultReporterFactory forkedReporterFactory = new DefaultReporterFactory( startupReportConfiguration );
+        DefaultReporterFactory forkedReporterFactory = new DefaultReporterFactory( startupReportConfiguration, log );
         defaultReporterFactories.add( forkedReporterFactory );
         TestLessInputStreamBuilder builder = new TestLessInputStreamBuilder();
         PropertiesWrapper props = new PropertiesWrapper( providerProperties );
         TestLessInputStream stream = builder.build();
-        ForkClient forkClient =
-            new ForkClient( forkedReporterFactory, startupReportConfiguration.getTestVmSystemProperties(), stream );
+        Properties sysProps = startupReportConfiguration.getTestVmSystemProperties();
+        ForkClient forkClient = new ForkClient( forkedReporterFactory, sysProps, stream, log );
         Thread shutdown = createImmediateShutdownHookThread( builder, providerConfiguration.getShutdown() );
         ScheduledFuture<?> ping = triggerPingTimerForShutdown( builder );
         try
@@ -318,12 +319,12 @@ public class ForkStarter
                     public RunResult call()
                         throws Exception
                     {
-                        DefaultReporterFactory reporter = new DefaultReporterFactory( startupReportConfiguration );
+                        DefaultReporterFactory reporter = new DefaultReporterFactory( startupReportConfiguration, log );
                         defaultReporterFactories.add( reporter );
 
                         Properties vmProps = startupReportConfiguration.getTestVmSystemProperties();
 
-                        ForkClient forkClient = new ForkClient( reporter, vmProps, testProvidingInputStream )
+                        ForkClient forkClient = new ForkClient( reporter, vmProps, testProvidingInputStream, log )
                         {
                             @Override
                             protected void stopOnNextTest()
@@ -383,11 +384,11 @@ public class ForkStarter
                         throws Exception
                     {
                         DefaultReporterFactory forkedReporterFactory =
-                            new DefaultReporterFactory( startupReportConfiguration );
+                            new DefaultReporterFactory( startupReportConfiguration, log );
                         defaultReporterFactories.add( forkedReporterFactory );
                         Properties vmProps = startupReportConfiguration.getTestVmSystemProperties();
                         ForkClient forkClient = new ForkClient( forkedReporterFactory, vmProps,
-                                                                builder.getImmediateCommands() )
+                                                                      builder.getImmediateCommands(), log )
                         {
                             @Override
                             protected void stopOnNextTest()
@@ -533,11 +534,8 @@ public class ForkStarter
             join( bootClasspathConfiguration, startupConfiguration.getClasspathConfiguration().getTestClasspath() ),
             startupConfiguration.getClasspathConfiguration().getProviderClasspath() );
 
-        if ( log.isDebugEnabled() )
-        {
-            log.debug( bootClasspath.getLogMessage( "boot" ) );
-            log.debug( bootClasspath.getCompactLogMessage( "boot(compact)" ) );
-        }
+        log.debug( bootClasspath.getLogMessage( "boot" ) );
+        log.debug( bootClasspath.getCompactLogMessage( "boot(compact)" ) );
 
         OutputStreamFlushableCommandline cli =
             forkConfiguration.createCommandLine( bootClasspath.getClassPath(), startupConfiguration, forkNumber );
@@ -558,10 +556,7 @@ public class ForkStarter
         final CloseableCloser closer =
                 new CloseableCloser( threadedStreamConsumer, requireNonNull( testProvidingInputStream, "null param" ) );
 
-        if ( forkConfiguration.isDebug() )
-        {
-            System.out.println( "Forking command line: " + cli );
-        }
+        log.debug( "Forking command line: " + cli );
 
         RunResult runResult = null;
 
@@ -569,7 +564,7 @@ public class ForkStarter
         {
             CommandLineCallable future =
                 executeCommandLineAsCallable( cli, testProvidingInputStream, threadedStreamConsumer,
-                                              threadedStreamConsumer, 0, closer,
+                                              new NativeStdErrStreamConsumer(), 0, closer,
                                               Charset.forName( FORK_STREAM_CHARSET_NAME ) );
 
             currentForkClients.add( forkClient );
@@ -630,7 +625,7 @@ public class ForkStarter
             ClassLoader unifiedClassLoader = classpathConfiguration.createMergedClassLoader();
 
             CommonReflector commonReflector = new CommonReflector( unifiedClassLoader );
-            Object reporterFactory = commonReflector.createReportingReporterFactory( startupReportConfiguration );
+            Object reporterFactory = commonReflector.createReportingReporterFactory( startupReportConfiguration, log );
 
             ProviderFactory providerFactory =
                 new ProviderFactory( startupConfiguration, providerConfiguration, unifiedClassLoader, reporterFactory );

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ProviderDetector.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ProviderDetector.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ProviderDetector.java
index 7af0103..3b93eff 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ProviderDetector.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ProviderDetector.java
@@ -19,20 +19,12 @@ package org.apache.maven.plugin.surefire.booterclient;
  * under the License.
  */
 
+import org.apache.maven.surefire.spi.ServiceLoader;
+
 import javax.annotation.Nonnull;
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.HashSet;
 import java.util.Set;
 
-import static java.lang.Character.isJavaIdentifierPart;
-import static java.lang.Character.isJavaIdentifierStart;
-import static java.util.Collections.emptySet;
-
 /**
  * @author Stephen Conolly
  * @author Kristian Rosenvold
@@ -40,93 +32,12 @@ import static java.util.Collections.emptySet;
  */
 public final class ProviderDetector
 {
+    private final ServiceLoader spi = new ServiceLoader();
 
-    @Nonnull public static Set<String> getServiceNames( Class<?> clazz, ClassLoader classLoader )
-        throws IOException
-    {
-        final String resourceName = "META-INF/services/" + clazz.getName();
-
-        if ( classLoader == null )
-        {
-            return emptySet();
-        }
-        final Enumeration<URL> urlEnumeration = classLoader.getResources( resourceName );
-        return getNames( urlEnumeration );
-    }
-
-
-    /**
-     * Method loadServices loads the services of a class that are
-     * defined using the SPI mechanism.
-     *
-     * @param urlEnumeration The urls from the resource
-     * @return The set of service provider names
-     * @throws IOException When reading the streams fails
-     */
     @Nonnull
-    @SuppressWarnings( "checkstyle:innerassignment" )
-    private static Set<String> getNames( final Enumeration<URL> urlEnumeration )
-        throws IOException
-    {
-        final Set<String> names = new HashSet<String>();
-        nextUrl:
-        while ( urlEnumeration.hasMoreElements() )
-        {
-            final URL url = urlEnumeration.nextElement();
-            final BufferedReader reader = getReader( url );
-            try
-            {
-                for ( String line; ( line = reader.readLine() ) != null; )
-                {
-                    int ci = line.indexOf( '#' );
-                    if ( ci >= 0 )
-                    {
-                        line = line.substring( 0, ci );
-                    }
-                    line = line.trim();
-                    int n = line.length();
-                    if ( n == 0 )
-                    {
-                        continue; // next line
-                    }
-
-                    if ( line.indexOf( ' ' ) >= 0 || line.indexOf( '\t' ) >= 0 )
-                    {
-                        continue nextUrl; // next url
-                    }
-                    char cp = line.charAt( 0 ); // should use codePointAt but this was JDK1.3
-                    if ( !isJavaIdentifierStart( cp ) )
-                    {
-                        continue nextUrl; // next url
-                    }
-                    for ( int i = 1; i < n; i++ )
-                    {
-                        cp = line.charAt( i );  // should use codePointAt but this was JDK1.3
-                        if ( !isJavaIdentifierPart( cp ) && cp != '.' )
-                        {
-                            continue nextUrl; // next url
-                        }
-                    }
-                    if ( !names.contains( line ) )
-                    {
-                        names.add( line );
-                    }
-                }
-            }
-            finally
-            {
-                reader.close();
-            }
-        }
-
-        return names;
-    }
-
-    @Nonnull private static BufferedReader getReader( @Nonnull URL url )
-        throws IOException
+    public Set<String> lookupServiceNames( Class<?> clazz, ClassLoader classLoader )
+            throws IOException
     {
-        final InputStream inputStream = url.openStream();
-        final InputStreamReader inputStreamReader = new InputStreamReader( inputStream );
-        return new BufferedReader( inputStreamReader );
+        return spi.lookup( clazz, classLoader );
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
index 767962a..be3b09f 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java
@@ -23,27 +23,29 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.StringReader;
 import java.nio.ByteBuffer;
-import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Properties;
 import java.util.StringTokenizer;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream;
 import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
 import org.apache.maven.shared.utils.cli.StreamConsumer;
-import org.apache.maven.surefire.report.ConsoleLogger;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.ReporterException;
 import org.apache.maven.surefire.report.RunListener;
 import org.apache.maven.surefire.report.StackTraceWriter;
 
+import static java.lang.Integer.decode;
 import static java.lang.Integer.parseInt;
 import static java.lang.System.currentTimeMillis;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_BYE;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_CONSOLE;
+import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_DEBUG;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_ERROR;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_NEXT_TEST;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_STDERR;
@@ -58,6 +60,7 @@ import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TES
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_SUCCEEDED;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TESTSET_COMPLETED;
 import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TESTSET_STARTING;
+import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_WARNING;
 import static org.apache.maven.surefire.booter.Shutdown.KILL;
 import static org.apache.maven.surefire.report.CategorizedReportEntry.reportEntry;
 import static org.apache.maven.surefire.util.internal.StringUtils.isNotBlank;
@@ -75,30 +78,34 @@ public class ForkClient
     private static final long START_TIME_ZERO = 0L;
     private static final long START_TIME_NEGATIVE_TIMEOUT = -1L;
 
-    private final DefaultReporterFactory defaultReporterFactory;
-
-    private final NotifiableTestStream notifiableTestStream;
+    private final ConcurrentMap<Integer, RunListener> testSetReporters;
 
-    private final Map<Integer, RunListener> testSetReporters = new ConcurrentHashMap<Integer, RunListener>();
+    private final DefaultReporterFactory defaultReporterFactory;
 
     private final Properties testVmSystemProperties;
 
+    private final NotifiableTestStream notifiableTestStream;
+
     /**
      * <t>testSetStartedAt</t> is set to non-zero after received
      * {@link org.apache.maven.surefire.booter.ForkingRunListener#BOOTERCODE_TESTSET_STARTING test-set}.
      */
     private final AtomicLong testSetStartedAt = new AtomicLong( START_TIME_ZERO );
 
+    private final ConsoleLogger log;
+
     private volatile boolean saidGoodBye;
 
     private volatile StackTraceWriter errorInFork;
 
     public ForkClient( DefaultReporterFactory defaultReporterFactory, Properties testVmSystemProperties,
-                       NotifiableTestStream notifiableTestStream )
+                       NotifiableTestStream notifiableTestStream, ConsoleLogger log )
     {
+        testSetReporters = new ConcurrentHashMap<Integer, RunListener>();
         this.defaultReporterFactory = defaultReporterFactory;
         this.testVmSystemProperties = testVmSystemProperties;
         this.notifiableTestStream = notifiableTestStream;
+        this.log = log;
     }
 
     protected void stopOnNextTest()
@@ -158,7 +165,7 @@ public class ForkClient
             int comma = s.indexOf( ",", 3 );
             if ( comma < 0 )
             {
-                System.out.println( s );
+                log.warning( s );
                 return;
             }
             final int channelNumber = parseInt( s.substring( 2, comma ), 16 );
@@ -168,29 +175,37 @@ public class ForkClient
             switch ( operationId )
             {
                 case BOOTERCODE_TESTSET_STARTING:
-                    getOrCreateReporter( channelNumber ).testSetStarting( createReportEntry( remaining ) );
+                    getOrCreateReporter( channelNumber )
+                            .testSetStarting( createReportEntry( remaining ) );
                     setCurrentStartTime();
                     break;
                 case BOOTERCODE_TESTSET_COMPLETED:
-                    getOrCreateReporter( channelNumber ).testSetCompleted( createReportEntry( remaining ) );
+                    getOrCreateReporter( channelNumber )
+                            .testSetCompleted( createReportEntry( remaining ) );
                     break;
                 case BOOTERCODE_TEST_STARTING:
-                    getOrCreateReporter( channelNumber ).testStarting( createReportEntry( remaining ) );
+                    getOrCreateReporter( channelNumber )
+                            .testStarting( createReportEntry( remaining ) );
                     break;
                 case BOOTERCODE_TEST_SUCCEEDED:
-                    getOrCreateReporter( channelNumber ).testSucceeded( createReportEntry( remaining ) );
+                    getOrCreateReporter( channelNumber )
+                            .testSucceeded( createReportEntry( remaining ) );
                     break;
                 case BOOTERCODE_TEST_FAILED:
-                    getOrCreateReporter( channelNumber ).testFailed( createReportEntry( remaining ) );
+                    getOrCreateReporter( channelNumber )
+                            .testFailed( createReportEntry( remaining ) );
                     break;
                 case BOOTERCODE_TEST_SKIPPED:
-                    getOrCreateReporter( channelNumber ).testSkipped( createReportEntry( remaining ) );
+                    getOrCreateReporter( channelNumber )
+                            .testSkipped( createReportEntry( remaining ) );
                     break;
                 case BOOTERCODE_TEST_ERROR:
-                    getOrCreateReporter( channelNumber ).testError( createReportEntry( remaining ) );
+                    getOrCreateReporter( channelNumber )
+                            .testError( createReportEntry( remaining ) );
                     break;
                 case BOOTERCODE_TEST_ASSUMPTIONFAILURE:
-                    getOrCreateReporter( channelNumber ).testAssumptionFailure( createReportEntry( remaining ) );
+                    getOrCreateReporter( channelNumber )
+                            .testAssumptionFailure( createReportEntry( remaining ) );
                     break;
                 case BOOTERCODE_SYSPROPS:
                     int keyEnd = remaining.indexOf( "," );
@@ -198,7 +213,6 @@ public class ForkClient
                     StringBuilder value = new StringBuilder();
                     unescapeString( key, remaining.substring( 0, keyEnd ) );
                     unescapeString( value, remaining.substring( keyEnd + 1 ) );
-
                     synchronized ( testVmSystemProperties )
                     {
                         testVmSystemProperties.put( key.toString(), value.toString() );
@@ -211,7 +225,8 @@ public class ForkClient
                     writeTestOutput( channelNumber, remaining, false );
                     break;
                 case BOOTERCODE_CONSOLE:
-                    getOrCreateConsoleLogger( channelNumber ).info( createConsoleMessage( remaining ) );
+                    getOrCreateConsoleLogger( channelNumber )
+                            .info( createConsoleMessage( remaining ) );
                     break;
                 case BOOTERCODE_NEXT_TEST:
                     notifiableTestStream.provideNewTest();
@@ -225,19 +240,27 @@ public class ForkClient
                 case BOOTERCODE_STOP_ON_NEXT_TEST:
                     stopOnNextTest();
                     break;
+                case BOOTERCODE_DEBUG:
+                    getOrCreateConsoleLogger( channelNumber )
+                            .debug( createConsoleMessage( remaining ) );
+                    break;
+                case BOOTERCODE_WARNING:
+                    getOrCreateConsoleLogger( channelNumber )
+                            .warning( createConsoleMessage( remaining ) );
+                    break;
                 default:
-                    System.out.println( s );
+                    log.warning( s );
             }
         }
         catch ( NumberFormatException e )
         {
             // SUREFIRE-859
-            System.out.println( s );
+            log.warning( s );
         }
         catch ( NoSuchElementException e )
         {
             // SUREFIRE-859
-            System.out.println( s );
+            log.warning( s );
         }
         catch ( ReporterException e )
         {
@@ -245,7 +268,7 @@ public class ForkClient
         }
     }
 
-    private void writeTestOutput( final int channelNumber, final String remaining, boolean isStdout )
+    private void writeTestOutput( final int channelNumber, final String remaining, final boolean isStdout )
     {
         int csNameEnd = remaining.indexOf( ',' );
         String charsetName = remaining.substring( 0, csNameEnd );
@@ -255,7 +278,6 @@ public class ForkClient
         if ( unescaped.hasArray() )
         {
             byte[] convertedBytes = unescaped.array();
-
             getOrCreateConsoleOutputReceiver( channelNumber )
                 .writeTestOutput( convertedBytes, unescaped.position(), unescaped.remaining(), isStdout );
         }
@@ -263,7 +285,6 @@ public class ForkClient
         {
             byte[] convertedBytes = new byte[unescaped.remaining()];
             unescaped.get( convertedBytes, 0, unescaped.remaining() );
-
             getOrCreateConsoleOutputReceiver( channelNumber )
                 .writeTestOutput( convertedBytes, 0, convertedBytes.length, isStdout );
         }
@@ -294,7 +315,7 @@ public class ForkClient
             String group = nullableCsv( tokens.nextToken() );
             String message = nullableCsv( tokens.nextToken() );
             String elapsedStr = tokens.nextToken();
-            Integer elapsed = "null".equals( elapsedStr ) ? null : Integer.decode( elapsedStr );
+            Integer elapsed = "null".equals( elapsedStr ) ? null : decode( elapsedStr );
             final StackTraceWriter stackTraceWriter =
                 tokens.hasMoreTokens() ? deserializeStackTraceWriter( tokens ) : null;
 
@@ -344,7 +365,11 @@ public class ForkClient
         if ( reporter == null )
         {
             reporter = defaultReporterFactory.createReporter();
-            testSetReporters.put( channelNumber, reporter );
+            RunListener old = testSetReporters.putIfAbsent( channelNumber, reporter );
+            if ( old != null )
+            {
+                reporter = old;
+            }
         }
         return reporter;
     }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/6a79127a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java
new file mode 100644
index 0000000..84ca474
--- /dev/null
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/NativeStdErrStreamConsumer.java
@@ -0,0 +1,38 @@
+package org.apache.maven.plugin.surefire.booterclient.output;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.shared.utils.cli.StreamConsumer;
+
+/**
+ * Used by forked JMV, see {@link org.apache.maven.plugin.surefire.booterclient.ForkStarter}.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.19.2
+ * @see org.apache.maven.plugin.surefire.booterclient.ForkStarter
+ */
+public final class NativeStdErrStreamConsumer
+    implements StreamConsumer
+{
+    public void consumeLine( String line )
+    {
+        System.err.println( line );
+    }
+}