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     @Override
263     public void mojoStarted( ExecutionEvent event )
264     {
265         if ( logger.isInfoEnabled() )
266         {
267             StringBuilder buffer = new StringBuilder( 128 );
268 
269             buffer.append( "--- " );
270             append( buffer, event.getMojoExecution() );
271             append( buffer, event.getProject() );
272             buffer.append( " ---" );
273 
274             logger.info( "" );
275             logger.info( buffer.toString() );
276         }
277     }
278 
279     @Override
280     public void forkStarted( ExecutionEvent event )
281     {
282         if ( logger.isInfoEnabled() )
283         {
284             StringBuilder buffer = new StringBuilder( 128 );
285 
286             buffer.append( ">>> " );
287             append( buffer, event.getMojoExecution() );
288             append( buffer, event.getProject() );
289             buffer.append( " >>>" );
290 
291             logger.info( "" );
292             logger.info( buffer.toString() );
293         }
294     }
295 
296     @Override
297     public void forkSucceeded( ExecutionEvent event )
298     {
299         if ( logger.isInfoEnabled() )
300         {
301             StringBuilder buffer = new StringBuilder( 128 );
302 
303             buffer.append( "<<< " );
304             append( buffer, event.getMojoExecution() );
305             append( buffer, event.getProject() );
306             buffer.append( " <<<" );
307 
308             logger.info( "" );
309             logger.info( buffer.toString() );
310         }
311     }
312 
313     private void append( StringBuilder buffer, MojoExecution me )
314     {
315         buffer.append( me.getArtifactId() ).append( ':' ).append( me.getVersion() );
316         buffer.append( ':' ).append( me.getGoal() );
317         if ( me.getExecutionId() != null )
318         {
319             buffer.append( " (" ).append( me.getExecutionId() ).append( ')' );
320         }
321     }
322 
323     private void append( StringBuilder buffer, MavenProject project )
324     {
325         buffer.append( " @ " ).append( project.getArtifactId() );
326     }
327 
328     @Override
329     public void forkedProjectStarted( ExecutionEvent event )
330     {
331         if ( logger.isInfoEnabled() && event.getMojoExecution().getForkedExecutions().size() > 1 )
332         {
333             logger.info( chars( ' ', LINE_LENGTH ) );
334             logger.info( chars( '>', LINE_LENGTH ) );
335 
336             logger.info( "Forking " + event.getProject().getName() + " " + event.getProject().getVersion() );
337 
338             logger.info( chars( '>', LINE_LENGTH ) );
339         }
340     }
341 
342 }