Ketan's Musings

Where he blogs about his eclipse musings

Composite Logger for Ant

with 3 comments

When doing long builds in CruiseControl, ant build logs are generally logged using the XmlLogger.

In certain cases, say for example when the build is taking longer than usual, and needs to be killed/stopped, the XmlLogger does not flush contents to disk.

It would be nice if there is some sort of a composite logger than can chain any logger along with the XmlLogger.

I just happened to write one sometime today. This is the source code for a CompositeLogger that logs to a default logger, and the XmlLogger. This needs the environment variable ANT_LOG_PREFIX to be set (there’s no better way I can think of)

package com.thoughtworks.ant.logger;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;

import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildLogger;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.XmlLogger;

/**
 * @author Ketan Padegaonkar
 */
public class CompositeAntLogger implements BuildLogger {

        private ArrayList       loggers;
        private String          logPrefix;
        private PrintStream     out;

        public CompositeAntLogger() {
                checkLogPrefix();
                createLoggers();
        }

        public void setEmacsMode(boolean emacsMode) {
                for (Iterator iterator = loggers.iterator(); iterator.hasNext();) {
                        BuildLogger logger = (BuildLogger) iterator.next();
                        logger.setEmacsMode(emacsMode);
                }
        }

        public void buildFinished(BuildEvent event) {
                for (Iterator iterator = loggers.iterator(); iterator.hasNext();) {
                        BuildLogger logger = (BuildLogger) iterator.next();
                        logger.buildFinished(event);
                }
        }

        public void buildStarted(BuildEvent event) {
                for (Iterator iterator = loggers.iterator(); iterator.hasNext();) {
                        BuildLogger logger = (BuildLogger) iterator.next();
                        logger.buildStarted(event);
                }
        }

        public void messageLogged(BuildEvent event) {
                for (Iterator iterator = loggers.iterator(); iterator.hasNext();) {
                        BuildLogger logger = (BuildLogger) iterator.next();
                        logger.messageLogged(event);
                }

        }

        public void targetFinished(BuildEvent event) {
                for (Iterator iterator = loggers.iterator(); iterator.hasNext();) {
                        BuildLogger logger = (BuildLogger) iterator.next();
                        logger.targetFinished(event);
                }
        }

        public void targetStarted(BuildEvent event) {
                for (Iterator iterator = loggers.iterator(); iterator.hasNext();) {
                        BuildLogger logger = (BuildLogger) iterator.next();
                        logger.targetStarted(event);
                }
        }

        public void taskFinished(BuildEvent event) {
                for (Iterator iterator = loggers.iterator(); iterator.hasNext();) {
                        BuildLogger logger = (BuildLogger) iterator.next();
                        logger.taskFinished(event);
                }
        }

        public void taskStarted(BuildEvent event) {
                for (Iterator iterator = loggers.iterator(); iterator.hasNext();) {
                        BuildLogger logger = (BuildLogger) iterator.next();
                        logger.taskStarted(event);
                }
        }

        public void setMessageOutputLevel(int level) {
                for (Iterator iterator = loggers.iterator(); iterator.hasNext();) {
                        BuildLogger logger = (BuildLogger) iterator.next();
                        logger.setMessageOutputLevel(level);
                }
        }

        public void setOutputPrintStream(PrintStream output) {
                // do nothing
        }

        public void setErrorPrintStream(PrintStream err) {
                // do nothing
        }

        private void createLoggers() {
                loggers = new ArrayList();
                try {
                        loggers.add(createDefaultLogger());
                        loggers.add(createXmlLogger());
                } catch (FileNotFoundException e) {
                        throw new BuildException("The loggers could not open the file", e);
                }
        }

        private void checkLogPrefix() {
                logPrefix = System.getenv("ANT_LOG_PREFIX");
                if (logPrefix == null || logPrefix.trim().length() == 0)
                        throw new BuildException("You need to set the environment variable ANT_LOG_PREFIX.");
        }

        private DefaultLogger createDefaultLogger() throws FileNotFoundException {
                DefaultLogger logger = new DefaultLogger();
                out = new PrintStream(new FileOutputStream(logPrefix + ".txt"));
                logger.setOutputPrintStream(out);
                logger.setErrorPrintStream(out);
                return logger;
        }

        private XmlLogger createXmlLogger() throws FileNotFoundException {
                XmlLogger logger = new XmlLogger();
                out = new PrintStream(new FileOutputStream(logPrefix + ".xml"));
                logger.setOutputPrintStream(out);
                logger.setErrorPrintStream(out);
                return logger;
        }
}

Written by Ketan

April 4th, 2007 at 7:24 pm

3 Responses to 'Composite Logger for Ant'

Subscribe to comments with RSS or TrackBack to 'Composite Logger for Ant'.

  1. Nice solution. On our current project we solved the problem in a different way: The top of our build.xml has an ant record statement that starts logging to a text file.

    End result is the same; one text file that is “tailable”, and the XML log output for CC.

    Tim

    8 Apr 07 at 2:27 pm

  2. Very nice solution. Could you point me to a way in which to include this in my CruiseControl implementation?

    Andrew

    13 Nov 09 at 12:15 am

  3. You need to create a jar with the CompositeAntLogger class file and put it in your ant’s lib dir.

    To run ant with this listener, you need to start ant with the -logger option:

    $ ant -logger com.thoughtworks.ant.logger.CompositeAntLogger

    Ketan

    27 Jan 10 at 9:48 pm

Leave a Reply

IMPORTANT! To be able to proceed, you need to solve the following simple math (so we know that you are a human) :-)

What is 9 + 14 ?
Please leave these two fields as-is: