View Javadoc

1   package org.apache.maven.cli;
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 java.util.Date;
23  
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.codehaus.plexus.logging.Logger;
34  
35  /**
36   * Logs execution events to a user-supplied logger.
37   *
38   * @author Benjamin Bentmann
39   */
40  public class ExecutionEventLogger
41      extends AbstractExecutionListener
42  {
43      private final Logger logger;
44  
45      private static final int LINE_LENGTH = 72;
46  
47      public ExecutionEventLogger( Logger logger )
48      {
49          if ( logger == null )
50          {
51              throw new IllegalArgumentException( "logger missing" );
52          }
53  
54          this.logger = logger;
55      }
56  
57      private static String chars( char c, int count )
58      {
59          StringBuilder buffer = new StringBuilder( count );
60  
61          for ( int i = count; i > 0; i-- )
62          {
63              buffer.append( c );
64          }
65  
66          return buffer.toString();
67      }
68  
69      private static String getFormattedTime( long time )
70      {
71          // NOTE: DateFormat is not suitable to format timespans of 24h+
72  
73          long h = time / ( 60 * 60 * 1000 );
74          long m = ( time - h * 60 * 60 * 1000 ) / ( 60 * 1000 );
75          long s = ( time - h * 60 * 60 * 1000 - m * 60 * 1000 ) / 1000;
76          long ms = time % 1000;
77  
78          String format;
79          if ( h > 0 )
80          {
81              format = "%1$d:%2$02d:%3$02d.%4$03ds";
82          }
83          else if ( m > 0 )
84          {
85              format = "%2$d:%3$02d.%4$03ds";
86          }
87          else
88          {
89              format = "%3$d.%4$03ds";
90          }
91  
92          return String.format( format, h, m, s, ms );
93      }
94  
95      @Override
96      public void projectDiscoveryStarted( ExecutionEvent event )
97      {
98          if ( logger.isInfoEnabled() )
99          {
100             logger.info( "Scanning for projects..." );
101         }
102     }
103 
104     @Override
105     public void sessionStarted( ExecutionEvent event )
106     {
107         if ( logger.isInfoEnabled() && event.getSession().getProjects().size() > 1 )
108         {
109             logger.info( chars( '-', LINE_LENGTH ) );
110 
111             logger.info( "Reactor Build Order:" );
112 
113             logger.info( "" );
114 
115             for ( MavenProject project : event.getSession().getProjects() )
116             {
117                 logger.info( project.getName() );
118             }
119         }
120     }
121 
122     @Override
123     public void sessionEnded( ExecutionEvent event )
124     {
125         if ( logger.isInfoEnabled() )
126         {
127             if ( event.getSession().getProjects().size() > 1 )
128             {
129                 logReactorSummary( event.getSession() );
130             }
131 
132             logResult( event.getSession() );
133 
134             logStats( event.getSession() );
135 
136             logger.info( chars( '-', LINE_LENGTH ) );
137         }
138     }
139 
140     private void logReactorSummary( MavenSession session )
141     {
142         logger.info( chars( '-', LINE_LENGTH ) );
143 
144         logger.info( "Reactor Summary:" );
145 
146         logger.info( "" );
147 
148         MavenExecutionResult result = session.getResult();
149 
150         for ( MavenProject project : session.getProjects() )
151         {
152             StringBuilder buffer = new StringBuilder( 128 );
153 
154             buffer.append( project.getName() );
155 
156             buffer.append( ' ' );
157             while ( buffer.length() < LINE_LENGTH - 21 )
158             {
159                 buffer.append( '.' );
160             }
161             buffer.append( ' ' );
162 
163             BuildSummary buildSummary = result.getBuildSummary( project );
164 
165             if ( buildSummary == null )
166             {
167                 buffer.append( "SKIPPED" );
168             }
169             else if ( buildSummary instanceof BuildSuccess )
170             {
171                 buffer.append( "SUCCESS [" );
172                 buffer.append( getFormattedTime( buildSummary.getTime() ) );
173                 buffer.append( "]" );
174             }
175             else if ( buildSummary instanceof BuildFailure )
176             {
177                 buffer.append( "FAILURE [" );
178                 buffer.append( getFormattedTime( buildSummary.getTime() ) );
179                 buffer.append( "]" );
180             }
181 
182             logger.info( buffer.toString() );
183         }
184     }
185 
186     private void logResult( MavenSession session )
187     {
188         logger.info( chars( '-', LINE_LENGTH ) );
189 
190         if ( session.getResult().hasExceptions() )
191         {
192             logger.info( "BUILD FAILURE" );
193         }
194         else
195         {
196             logger.info( "BUILD SUCCESS" );
197         }
198     }
199 
200     private void logStats( MavenSession session )
201     {
202         logger.info( chars( '-', LINE_LENGTH ) );
203 
204         Date finish = new Date();
205 
206         long time = finish.getTime() - session.getRequest().getStartTime().getTime();
207 
208         String wallClock = session.getRequest().isThreadConfigurationPresent() ? " (Wall Clock)" : "";
209 
210         logger.info( "Total time: " + getFormattedTime( time ) + wallClock );
211 
212         logger.info( "Finished at: " + finish );
213 
214         System.gc();
215 
216         Runtime r = Runtime.getRuntime();
217 
218         long MB = 1024 * 1024;
219 
220         logger.info( "Final Memory: " + ( r.totalMemory() - r.freeMemory() ) / MB + "M/" + r.totalMemory() / MB + "M" );
221     }
222 
223     @Override
224     public void projectSkipped( ExecutionEvent event )
225     {
226         if ( logger.isInfoEnabled() )
227         {
228             logger.info( chars( ' ', LINE_LENGTH ) );
229             logger.info( chars( '-', LINE_LENGTH ) );
230 
231             logger.info( "Skipping " + event.getProject().getName() );
232             logger.info( "This project has been banned from the build due to previous failures." );
233 
234             logger.info( chars( '-', LINE_LENGTH ) );
235         }
236     }
237 
238     @Override
239     public void projectStarted( ExecutionEvent event )
240     {
241         if ( logger.isInfoEnabled() )
242         {
243             logger.info( chars( ' ', LINE_LENGTH ) );
244             logger.info( chars( '-', LINE_LENGTH ) );
245 
246             logger.info( "Building " + event.getProject().getName() + " " + event.getProject().getVersion() );
247 
248             logger.info( chars( '-', LINE_LENGTH ) );
249         }
250     }
251 
252     @Override
253     public void mojoSkipped( ExecutionEvent event )
254     {
255         if ( logger.isWarnEnabled() )
256         {
257             logger.warn( "Goal " + event.getMojoExecution().getGoal()
258                 + " requires online mode for execution but Maven is currently offline, skipping" );
259         }
260     }
261 
262     /**
263      * <pre>--- mojo-artifactId:version:goal (mojo-executionId) @ project-artifactId ---</pre>
264      */
265     @Override
266     public void mojoStarted( ExecutionEvent event )
267     {
268         if ( logger.isInfoEnabled() )
269         {
270             StringBuilder buffer = new StringBuilder( 128 );
271 
272             buffer.append( "--- " );
273             append( buffer, event.getMojoExecution() );
274             append( buffer, event.getProject() );
275             buffer.append( " ---" );
276 
277             logger.info( "" );
278             logger.info( buffer.toString() );
279         }
280     }
281 
282     /**
283      * <pre>>>> mojo-artifactId:version:goal (mojo-executionId) @ project-artifactId >>></pre>
284      */
285     @Override
286     public void forkStarted( ExecutionEvent event )
287     {
288         if ( logger.isInfoEnabled() )
289         {
290             StringBuilder buffer = new StringBuilder( 128 );
291 
292             buffer.append( ">>> " );
293             append( buffer, event.getMojoExecution() );
294             append( buffer, event.getProject() );
295             buffer.append( " >>>" );
296 
297             logger.info( "" );
298             logger.info( buffer.toString() );
299         }
300     }
301 
302     /**
303      * <pre>&lt;&lt;&lt; mojo-artifactId:version:goal (mojo-executionId) @ project-artifactId &lt;&lt;&lt;</pre>
304      */
305     @Override
306     public void forkSucceeded( ExecutionEvent event )
307     {
308         if ( logger.isInfoEnabled() )
309         {
310             StringBuilder buffer = new StringBuilder( 128 );
311 
312             buffer.append( "<<< " );
313             append( buffer, event.getMojoExecution() );
314             append( buffer, event.getProject() );
315             buffer.append( " <<<" );
316 
317             logger.info( "" );
318             logger.info( buffer.toString() );
319         }
320     }
321 
322     private void append( StringBuilder buffer, MojoExecution me )
323     {
324         buffer.append( me.getArtifactId() ).append( ':' ).append( me.getVersion() );
325         buffer.append( ':' ).append( me.getGoal() );
326         if ( me.getExecutionId() != null )
327         {
328             buffer.append( " (" ).append( me.getExecutionId() ).append( ')' );
329         }
330     }
331 
332     private void append( StringBuilder buffer, MavenProject project )
333     {
334         buffer.append( " @ " ).append( project.getArtifactId() );
335     }
336 
337     @Override
338     public void forkedProjectStarted( ExecutionEvent event )
339     {
340         if ( logger.isInfoEnabled() && event.getMojoExecution().getForkedExecutions().size() > 1 )
341         {
342             logger.info( chars( ' ', LINE_LENGTH ) );
343             logger.info( chars( '>', LINE_LENGTH ) );
344 
345             logger.info( "Forking " + event.getProject().getName() + " " + event.getProject().getVersion() );
346 
347             logger.info( chars( '>', LINE_LENGTH ) );
348         }
349     }
350 
351 }