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