You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by Steve Loughran <st...@apache.org> on 2007/05/18 14:32:48 UTC
BigProjectLogger
I'm just coding up a new logger to make it easier to analyse big
projects built with subant. From the patched listeners.html:
<h3><a name="BigProjectLogger">BigProjectLogger</a></h3>
<p>
This logger is designed to make examining the logs of a big build easier,
especially those run under continuous integration tools. It
</p>
<ol>
<li>Includes the build finished timestamp of the TimeStamp logger</li>
<li>Omits logging the names of all targets that have no direct task
output</li>
<li>Includes the name of the project when printing a target</li>
</ol>
<p>
This is useful when using <subant> to build a large project
from many smaller projects -the output shows which particular
project is building. Here is an example
</p>
<pre>
kernel.init:
[echo] building /home/ant/examples/kernel/lib/kernel-3.10.jar
... (many lines of log output omitted) ...
kernel.all:
[echo] completed kernel build
tasks.init:
[echo] building /home/ant/examples/tasks/lib/tasks-3.10.jar
[echo] system.tests.enabled=true
</pre>
One question I have here, is : how should I present teh project name.
(a) with a . for example: kernel.init and kernel.common.init
-good for simple things, but imports can confuse it
(b) a / for example: kernel/init and kernel/common.init
-may cause confusion as project names != dir names
(c) colon for example: kernel:init and kernel:common.init
(d) brackets [kernel]:init and [kernel]:common.init
-makes targets look like task output
(e) XML Qualified names :) {kernel}#init and {somewith with
spaces}#common.init
-awful
I'd started off with the '.' symbol, but worry that overriden imported
projects would introduce confusion... and you can have spaces in a
project name (which could trigger us quoting them)
I suppose I could make the separator and such like configurable through
project properties.
-steve
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org
Re: BigProjectLogger
Posted by Steve Loughran <st...@apache.org>.
Dominique Devienne wrote:
> On 5/18/07, Steve Loughran <st...@apache.org> wrote:
>> OK. You've done what I've done, except with some stacking.
>
> I had too, some of my builds had 3 or 4 levels, Makefile-style. Which
> is not that surprising, since it was building mostly native stuff with
> <ac:cc>. I think it's essential to do the stacking.
>
> Someone remarked at the time it wasn't safe in the face of <parallel>,
> but this wasn't a pb for me. --DD
yes, I saw that when I looked at it. Now, if we defined one of two
things we could address this
1. have a ProjectInfo class that includes (name,location URI,resource
ref,basedir) of a build file. Attach one to every project, give child
project's info about their parent
2. have every Project retain a ref to its parent.
#2 worries me from a memory perspective; as long as each child project
has a lifespan shorter than its parent all is well. Some embedded uses
could maybe do bad things. Also it lets people write tasks that
manipulate their parent and grandparent's state.
-steve
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org
Re: BigProjectLogger
Posted by Dominique Devienne <dd...@gmail.com>.
On 5/18/07, Steve Loughran <st...@apache.org> wrote:
> OK. You've done what I've done, except with some stacking.
I had too, some of my builds had 3 or 4 levels, Makefile-style. Which
is not that surprising, since it was building mostly native stuff with
<ac:cc>. I think it's essential to do the stacking.
Someone remarked at the time it wasn't safe in the face of <parallel>,
but this wasn't a pb for me. --DD
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org
Re: BigProjectLogger
Posted by Steve Loughran <st...@apache.org>.
Dominique Devienne wrote:
> On 5/18/07, Steve Loughran <st...@apache.org> wrote:
>> One question I have here, is : how should I present teh project name.
>>
>> (a) with a . for example: kernel.init and kernel.common.init
>> -good for simple things, but imports can confuse it
>> (b) a / for example: kernel/init and kernel/common.init
>> -may cause confusion as project names != dir names
>> (c) colon for example: kernel:init and kernel:common.init
>>
>> (d) brackets [kernel]:init and [kernel]:common.init
>> -makes targets look like task output
>> (e) XML Qualified names :) {kernel}#init and {somewith with
>> spaces}#common.init
>> -awful
>
> For NoBannerSubBuildLogger, for reference, I used
>
> target-name: [main-project-name/level1-subbuild/level2-subsubbuild]
>
> at a fixed offset unless the target name was too long.
OK. You've done what I've done, except with some stacking. Now, if
projects had an optional parent project, we could work it out dynamically.
>
>
> import java.util.Stack;
>
> import org.apache.tools.ant.Target;
> import org.apache.tools.ant.Project;
> import org.apache.tools.ant.BuildEvent;
> import org.apache.tools.ant.DefaultLogger;
> import org.apache.tools.ant.util.StringUtils;
>
> /**
> * Build logger that allows to make sense of the nesting structure
> * generated by the use of <ant> and <subant> in Ant build
> files.
> * <p>
> * The target banner (the target name followed by a colon, all in its own
> line)
> * will not be printed until that target's tasks output any kind of message.
> * This greatly simplifies the build output for all those targets that do
> not
> * execute, either because they are prevented to from their 'if' or 'unless'
> * attributes, or because all their input files are up-to-date versus their
> * output files.
> * <p>
> * In addition, the target banner (when output) will be postfixed with the
> * project path that lead to its execution, i.e. the list of project names
> * that were started using either <ant> and <subant>. Assuming
> * one calls the build target of 3 different sub-builds called A, B, and C
> * all called from a master build, one could get an output as follows:
> * <pre>
> * Buildfile: master.xml
> *
> * build: [master/A]
> * Compiling 19 source file to /acme/A/classes
> *
> * build: [master/B]
> * Compiling 15 source file to /acme/B/classes
> *
> * build: [master/C]
> * Compiling 12 source file to /acme/C/classes
> *
> * BUILD SUCCESSFUL
> * Total time: 8 seconds
> * </pre>
> * <p>
> * Inspired from NoBannerLogger by Peter Donald.
> */
> public class NoBannerSubBuildLogger
> extends DefaultLogger {
>
> /** The cached current target name, awaiting to be possibly printed. */
> private String _targetName;
>
> /** The stack of nesting Ant projects. */
> private Stack _projects = new Stack();
>
> /** The private buffer of this logger. */
> protected StringBuffer _buffer = new StringBuffer(128);
>
> /**
> * Gets the target banner for a given target name.
> *
> * @param targetName the target name to get the banner for.
> * @return the full target banner name.
> */
> protected String getTargetBanner(String targetName) {
> _buffer.setLength(0);
>
> // Target banner as usual
> _buffer.append(StringUtils.LINE_SEP);
> _buffer.append(targetName);
> _buffer.append(':');
>
> // Postfix the project path
> fillToIndex(_buffer, 16, ' ', 1);
> _buffer.append('[');
> appendProjectPath(_buffer, '/');
> _buffer.append(']');
>
> // Return the full target banner (toString() in bugged in JDK 1.4.1)
> return _buffer.substring(0);
> }
>
> /**
> * Appends the current project path to a given buffer.
> *
> * @param buffer the string buffer to append to.
> * @param separator the project path separator to use.
> */
> protected void appendProjectPath(StringBuffer buffer, char separator) {
> final int count = _projects.size();
> for (int i = 0; i < count; ++i) {
> Project project = (Project)_projects.get(i);
> buffer.append(project.getName());
> buffer.append(separator);
> }
> if (count > 0) {
> buffer.setLength(_buffer.length()-1);
> }
> }
>
> /**
> * Fills a string buffer with a given character to reach a known length.
> *
> * @param buffer the string buffer to fill (Cannot be
> <code>null</code>).
> * @param column the column index to fill up to.
> * @param c the char to fill up with.
> * @param minLength the mininum number of character to add in case the
> * string buffer is already longer than <code>column</code>
> * @return the number of characters actually added.
> */
> protected static int fillToIndex(StringBuffer buffer, int column,
> char c, int minLength) {
> final int fillCount = Math.max(column - buffer.length(), minLength);
> for (int i = 0; i < fillCount; ++i) {
> buffer.append(c);
> }
> return fillCount;
> }
>
> /**
> * Records/caches the target name and its project just started.
> *
> * @param event the build event to extract the target from.
> */
> public void targetStarted(BuildEvent event) {
> Target target = event.getTarget();
> _targetName = target.getName();
> _projects.push(target.getProject());
> }
>
> /**
> * Cleans up the record/cache of the target name and its project.
> *
> * @param event the (ignored here) build event.
> */
> public void targetFinished(BuildEvent event) {
> _targetName = null;
> _projects.pop();
> }
>
> /**
> * Logs a task message, possibly displaying the target and project path
> * that led to its execution, if they were not displayed earlier.
> *
> * @param event the build event containing message information.
> * Must not be <code>null</code>.
> */
> public void messageLogged(BuildEvent event) {
> if (event.getPriority() > msgOutputLevel
> || null == event.getMessage()
> || (_targetName != null &&
> "".equals(event.getMessage().trim()))) {
> return;
> }
>
> if (_targetName != null) {
> out.println(getTargetBanner(_targetName));
> _targetName = null;
> }
>
> super.messageLogged(event);
> }
>
> } // END class NoBannerSubBuildLogger
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
> For additional commands, e-mail: dev-help@ant.apache.org
>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org
Re: BigProjectLogger
Posted by Dominique Devienne <dd...@gmail.com>.
On 5/18/07, Steve Loughran <st...@apache.org> wrote:
> One question I have here, is : how should I present teh project name.
>
> (a) with a . for example: kernel.init and kernel.common.init
> -good for simple things, but imports can confuse it
> (b) a / for example: kernel/init and kernel/common.init
> -may cause confusion as project names != dir names
> (c) colon for example: kernel:init and kernel:common.init
>
> (d) brackets [kernel]:init and [kernel]:common.init
> -makes targets look like task output
> (e) XML Qualified names :) {kernel}#init and {somewith with
> spaces}#common.init
> -awful
For NoBannerSubBuildLogger, for reference, I used
target-name: [main-project-name/level1-subbuild/level2-subsubbuild]
at a fixed offset unless the target name was too long.
import java.util.Stack;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.util.StringUtils;
/**
* Build logger that allows to make sense of the nesting structure
* generated by the use of <ant> and <subant> in Ant build files.
* <p>
* The target banner (the target name followed by a colon, all in its own line)
* will not be printed until that target's tasks output any kind of message.
* This greatly simplifies the build output for all those targets that do not
* execute, either because they are prevented to from their 'if' or 'unless'
* attributes, or because all their input files are up-to-date versus their
* output files.
* <p>
* In addition, the target banner (when output) will be postfixed with the
* project path that lead to its execution, i.e. the list of project names
* that were started using either <ant> and <subant>. Assuming
* one calls the build target of 3 different sub-builds called A, B, and C
* all called from a master build, one could get an output as follows:
* <pre>
* Buildfile: master.xml
*
* build: [master/A]
* Compiling 19 source file to /acme/A/classes
*
* build: [master/B]
* Compiling 15 source file to /acme/B/classes
*
* build: [master/C]
* Compiling 12 source file to /acme/C/classes
*
* BUILD SUCCESSFUL
* Total time: 8 seconds
* </pre>
* <p>
* Inspired from NoBannerLogger by Peter Donald.
*/
public class NoBannerSubBuildLogger
extends DefaultLogger {
/** The cached current target name, awaiting to be possibly printed. */
private String _targetName;
/** The stack of nesting Ant projects. */
private Stack _projects = new Stack();
/** The private buffer of this logger. */
protected StringBuffer _buffer = new StringBuffer(128);
/**
* Gets the target banner for a given target name.
*
* @param targetName the target name to get the banner for.
* @return the full target banner name.
*/
protected String getTargetBanner(String targetName) {
_buffer.setLength(0);
// Target banner as usual
_buffer.append(StringUtils.LINE_SEP);
_buffer.append(targetName);
_buffer.append(':');
// Postfix the project path
fillToIndex(_buffer, 16, ' ', 1);
_buffer.append('[');
appendProjectPath(_buffer, '/');
_buffer.append(']');
// Return the full target banner (toString() in bugged in JDK 1.4.1)
return _buffer.substring(0);
}
/**
* Appends the current project path to a given buffer.
*
* @param buffer the string buffer to append to.
* @param separator the project path separator to use.
*/
protected void appendProjectPath(StringBuffer buffer, char separator) {
final int count = _projects.size();
for (int i = 0; i < count; ++i) {
Project project = (Project)_projects.get(i);
buffer.append(project.getName());
buffer.append(separator);
}
if (count > 0) {
buffer.setLength(_buffer.length()-1);
}
}
/**
* Fills a string buffer with a given character to reach a known length.
*
* @param buffer the string buffer to fill (Cannot be <code>null</code>).
* @param column the column index to fill up to.
* @param c the char to fill up with.
* @param minLength the mininum number of character to add in case the
* string buffer is already longer than <code>column</code>
* @return the number of characters actually added.
*/
protected static int fillToIndex(StringBuffer buffer, int column,
char c, int minLength) {
final int fillCount = Math.max(column - buffer.length(), minLength);
for (int i = 0; i < fillCount; ++i) {
buffer.append(c);
}
return fillCount;
}
/**
* Records/caches the target name and its project just started.
*
* @param event the build event to extract the target from.
*/
public void targetStarted(BuildEvent event) {
Target target = event.getTarget();
_targetName = target.getName();
_projects.push(target.getProject());
}
/**
* Cleans up the record/cache of the target name and its project.
*
* @param event the (ignored here) build event.
*/
public void targetFinished(BuildEvent event) {
_targetName = null;
_projects.pop();
}
/**
* Logs a task message, possibly displaying the target and project path
* that led to its execution, if they were not displayed earlier.
*
* @param event the build event containing message information.
* Must not be <code>null</code>.
*/
public void messageLogged(BuildEvent event) {
if (event.getPriority() > msgOutputLevel
|| null == event.getMessage()
|| (_targetName != null && "".equals(event.getMessage().trim()))) {
return;
}
if (_targetName != null) {
out.println(getTargetBanner(_targetName));
_targetName = null;
}
super.messageLogged(event);
}
} // END class NoBannerSubBuildLogger
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org