View Javadoc
1   package org.apache.maven.cli.event;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import static org.apache.maven.cli.CLIReportingUtils.formatDuration;
23  import static org.apache.maven.cli.CLIReportingUtils.formatTimestamp;
24  import org.apache.maven.execution.AbstractExecutionListener;
25  import org.apache.maven.execution.BuildFailure;
26  import org.apache.maven.execution.BuildSuccess;
27  import org.apache.maven.execution.BuildSummary;
28  import org.apache.maven.execution.ExecutionEvent;
29  import org.apache.maven.execution.MavenExecutionResult;
30  import org.apache.maven.execution.MavenSession;
31  import org.apache.maven.plugin.MojoExecution;
32  import org.apache.maven.project.MavenProject;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  /**
37   * Logs execution events to logger, eventually user-supplied.
38   *
39   * @author Benjamin Bentmann
40   */
41  public class ExecutionEventLogger
42      extends AbstractExecutionListener
43  {
44      private final Logger logger;
45  
46      private static final int LINE_LENGTH = 72;
47      private static final int BUILD_TIME_DURATION_LENGTH = 9;
48  
49      public ExecutionEventLogger()
50      {
51          logger = LoggerFactory.getLogger( ExecutionEventLogger.class );
52      }
53  
54      // TODO should we deprecate?
55      public ExecutionEventLogger( Logger logger )
56      {
57          if ( logger == null )
58          {
59              throw new IllegalArgumentException( "logger missing" );
60          }
61  
62          this.logger = logger;
63      }
64  
65      private static String chars( char c, int count )
66      {
67          StringBuilder buffer = new StringBuilder( count );
68  
69          for ( int i = count; i > 0; i-- )
70          {
71              buffer.append( c );
72          }
73  
74          return buffer.toString();
75      }
76  
77      @Override
78      public void projectDiscoveryStarted( ExecutionEvent event )
79      {
80          if ( logger.isInfoEnabled() )
81          {
82              logger.info( "Scanning for projects..." );
83          }
84      }
85  
86      @Override
87      public void sessionStarted( ExecutionEvent event )
88      {
89          if ( logger.isInfoEnabled() && event.getSession().getProjects().size() > 1 )
90          {
91              logger.info( chars( '-', LINE_LENGTH ) );
92  
93              logger.info( "Reactor Build Order:" );
94  
95              logger.info( "" );
96  
97              for ( MavenProject project : event.getSession().getProjects() )
98              {
99                  logger.info( project.getName() );
100             }
101         }
102     }
103 
104     @Override
105     public void sessionEnded( ExecutionEvent event )
106     {
107         if ( logger.isInfoEnabled() )
108         {
109             if ( event.getSession().getProjects().size() > 1 )
110             {
111                 logReactorSummary( event.getSession() );
112             }
113 
114             logResult( event.getSession() );
115 
116             logStats( event.getSession() );
117 
118             logger.info( chars( '-', LINE_LENGTH ) );
119         }
120     }
121 
122     private void logReactorSummary( MavenSession session )
123     {
124         logger.info( chars( '-', LINE_LENGTH ) );
125 
126         logger.info( "Reactor Summary:" );
127 
128         logger.info( "" );
129 
130         MavenExecutionResult result = session.getResult();
131 
132         for ( MavenProject project : session.getProjects() )
133         {
134             StringBuilder buffer = new StringBuilder( 128 );
135 
136             buffer.append( project.getName() );
137 
138             buffer.append( ' ' );
139             while ( buffer.length() < LINE_LENGTH - 21 )
140             {
141                 buffer.append( '.' );
142             }
143             buffer.append( ' ' );
144 
145             BuildSummary buildSummary = result.getBuildSummary( project );
146 
147             if ( buildSummary == null )
148             {
149                 buffer.append( "SKIPPED" );
150             }
151             else if ( buildSummary instanceof BuildSuccess )
152             {
153                 buffer.append( "SUCCESS [" );
154                 String buildTimeDuration = formatDuration( buildSummary.getTime() );
155                 buffer.append( chars( ' ', BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length() ) );
156                 buffer.append( buildTimeDuration );
157                 buffer.append( "]" );
158             }
159             else if ( buildSummary instanceof BuildFailure )
160             {
161                 buffer.append( "FAILURE [" );
162                 String buildTimeDuration = formatDuration( buildSummary.getTime() );
163                 buffer.append( chars( ' ', BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length() ) );
164                 buffer.append( buildTimeDuration );
165                 buffer.append( "]" );
166             }
167 
168             logger.info( buffer.toString() );
169         }
170     }
171 
172     private void logResult( MavenSession session )
173     {
174         logger.info( chars( '-', LINE_LENGTH ) );
175 
176         if ( session.getResult().hasExceptions() )
177         {
178             logger.info( "BUILD FAILURE" );
179         }
180         else
181         {
182             logger.info( "BUILD SUCCESS" );
183         }
184     }
185 
186     private void logStats( MavenSession session )
187     {
188         logger.info( chars( '-', LINE_LENGTH ) );
189 
190         long finish = System.currentTimeMillis();
191 
192         long time = finish - session.getRequest().getStartTime().getTime();
193 
194         String wallClock = session.getRequest().getDegreeOfConcurrency() > 1 ? " (Wall Clock)" : "";
195 
196         logger.info( "Total time: " + formatDuration( time ) + wallClock );
197 
198         logger.info( "Finished at: " + formatTimestamp( finish ) );
199 
200         System.gc();
201 
202         Runtime r = Runtime.getRuntime();
203 
204         long MB = 1024 * 1024;
205 
206         logger.info( "Final Memory: " + ( r.totalMemory() - r.freeMemory() ) / MB + "M/" + r.totalMemory() / MB + "M" );
207     }
208 
209     @Override
210     public void projectSkipped( ExecutionEvent event )
211     {
212         if ( logger.isInfoEnabled() )
213         {
214             logger.info( chars( ' ', LINE_LENGTH ) );
215             logger.info( chars( '-', LINE_LENGTH ) );
216 
217             logger.info( "Skipping " + event.getProject().getName() );
218             logger.info( "This project has been banned from the build due to previous failures." );
219 
220             logger.info( chars( '-', LINE_LENGTH ) );
221         }
222     }
223 
224     @Override
225     public void projectStarted( ExecutionEvent event )
226     {
227         if ( logger.isInfoEnabled() )
228         {
229             logger.info( chars( ' ', LINE_LENGTH ) );
230             logger.info( chars( '-', LINE_LENGTH ) );
231 
232             logger.info( "Building " + event.getProject().getName() + " " + event.getProject().getVersion() );
233 
234             logger.info( chars( '-', LINE_LENGTH ) );
235         }
236     }
237 
238     @Override
239     public void mojoSkipped( ExecutionEvent event )
240     {
241         if ( logger.isWarnEnabled() )
242         {
243             logger.warn( "Goal " + event.getMojoExecution().getGoal()
244                 + " requires online mode for execution but Maven is currently offline, skipping" );
245         }
246     }
247 
248     /**
249      * <pre>--- mojo-artifactId:version:goal (mojo-executionId) @ project-artifactId ---</pre>
250      */
251     @Override
252     public void mojoStarted( ExecutionEvent event )
253     {
254         if ( logger.isInfoEnabled() )
255         {
256             StringBuilder buffer = new StringBuilder( 128 );
257 
258             buffer.append( "--- " );
259             append( buffer, event.getMojoExecution() );
260             append( buffer, event.getProject() );
261             buffer.append( " ---" );
262 
263             logger.info( "" );
264             logger.info( buffer.toString() );
265         }
266     }
267 
268     /**
269      * <pre>>>> mojo-artifactId:version:goal (mojo-executionId) @ project-artifactId >>></pre>
270      */
271     @Override
272     public void forkStarted( ExecutionEvent event )
273     {
274         if ( logger.isInfoEnabled() )
275         {
276             StringBuilder buffer = new StringBuilder( 128 );
277 
278             buffer.append( ">>> " );
279             append( buffer, event.getMojoExecution() );
280             append( buffer, event.getProject() );
281             buffer.append( " >>>" );
282 
283             logger.info( "" );
284             logger.info( buffer.toString() );
285         }
286     }
287 
288     /**
289      * <pre>&lt;&lt;&lt; mojo-artifactId:version:goal (mojo-executionId) @ project-artifactId &lt;&lt;&lt;</pre>
290      */
291     @Override
292     public void forkSucceeded( ExecutionEvent event )
293     {
294         if ( logger.isInfoEnabled() )
295         {
296             StringBuilder buffer = new StringBuilder( 128 );
297 
298             buffer.append( "<<< " );
299             append( buffer, event.getMojoExecution() );
300             append( buffer, event.getProject() );
301             buffer.append( " <<<" );
302 
303             logger.info( "" );
304             logger.info( buffer.toString() );
305         }
306     }
307 
308     private void append( StringBuilder buffer, MojoExecution me )
309     {
310         buffer.append( me.getArtifactId() ).append( ':' ).append( me.getVersion() );
311         buffer.append( ':' ).append( me.getGoal() );
312         if ( me.getExecutionId() != null )
313         {
314             buffer.append( " (" ).append( me.getExecutionId() ).append( ')' );
315         }
316     }
317 
318     private void append( StringBuilder buffer, MavenProject project )
319     {
320         buffer.append( " @ " ).append( project.getArtifactId() );
321     }
322 
323     @Override
324     public void forkedProjectStarted( ExecutionEvent event )
325     {
326         if ( logger.isInfoEnabled() && event.getMojoExecution().getForkedExecutions().size() > 1 )
327         {
328             logger.info( chars( ' ', LINE_LENGTH ) );
329             logger.info( chars( '>', LINE_LENGTH ) );
330 
331             logger.info( "Forking " + event.getProject().getName() + " " + event.getProject().getVersion() );
332 
333             logger.info( chars( '>', LINE_LENGTH ) );
334         }
335     }
336 
337 }