September 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Taking on Custom Ant Logging

  • November 16, 2006
  • By Rob Lybarger
  • Send Email »
  • More Articles »

Syslog Overview

Syslog is a common network service that allows a machine on the network to be a recipient of logging messages from multiple other machines on the network. For the current discussion, RFC 3164 is relevant and serves as the basis for my syslog implementation classes. One point to bear in mind is that, in addition to message severity levels (error, warning, etc), the syslog protocol also defines a "facility" which is rather like a category that the application that is emitting the log messages belongs to. A syslog server is commonly configured to send messages from different log facilities into different files (or possibly to forward them to another syslog server) so the exact destination of your syslog messages depends on the whim of the network administrator. (If this isn't you, then you might be relegated to simply read along.) Also, many facility values are reserved for special applications, although eight "local" facilities (notionally designed "local0" through "local7") are defined for your own use. Lastly, note that syslog servers can be configured to either listen for or disregard UDP-based messages. Mac OS X 10.4, for example, needs explicit configuration adjustments to log UDP syslog messages. I have included a link to a quick "howto" explaining what steps are needed for OS X 10.4. For most UNIX-derivatives, running the syslog daemon with the "-u" argument seems to be necessary, plus configuration of a file typically in the "/etc" directory.

Note: Mac OS X 10.4 seems to use the "local0" facility for firewall-based messages, so it would be wise to use one of the other unclaimed local facilities. You might spare yourself some grief by first checking if your syslog configuration is already using a particular local facility for some meaningful purpose before you hard-wire a custom listener to use it.

Syslog Implementation Classes

In the zip file accompanying this article are two classes: SyslogMessage and SyslogMessageFactory. I wrote these classes to get a rough implementation for a UDP-based remote syslog facility. The SyslogMessage class itself contains, among other things, the actual message text being logged and the message priority level. It also contains the working code to transmit a UDP packet to some syslog server. The other class, SyslogMessageFactory, is a factory-pattern helper class designed mainly to take some of the effort out of creating and configuring lots of SyslogMessage objects. A very simplified usage pattern for these follows:

  1. Create a new a SyslogMessageFactory object. Using the simplest constructor option, pass in some short name you want attached to your log messages. This constructor will assume the syslog server is running on your (the local) machine.
  2. Call the setFacility method on your factory object to set the facility value. Note that your syslog server may need explicit configuration to handle messages matching this facility value. You should use one of the eight ogMessage object. Valid options for code for these classes. I will admit up front, however, that comments are rather sparse.

The Ant BuildListener Implementation

Also included in the zip file accompanying this article is a class called SyslogListener. This is simply a class that directly implements Ant's BuildListener interface. A no-arg constructor is used to initialize a SyslogMessageFactory object before actual Ant log messages are dealt with. Ant then calls the various BuildListener interface methods as interesting events occur during the build. These methods in turn analyze the BuildEvent and use the factory object reference to create SyslogMessage objects, which are then transmitted. The following is a snippet of code from the SyslogListener class:

public class SyslogListener implements BuildListener {

  private SyslogMessageFactory factory = null;


  /* no-arg constructor called by Ant during startup */
  public SyslogListener() {
    factory = new SyslogMessageFactory("ant_demo");
    factory.setFacility(SyslogMessage.FACILITY_LOCAL_7);
  }


  /* convenience method to catch send()-related exceptions */
  private void deliverMessage(SyslogMessage message) {
    try {
      message.send();
    }
    catch (IOException ioe) {
      /* ignored for simplicity */
    }
  }


  /* BuildListener implementation methods start... */

  public void buildStarted(BuildEvent event) {
    String projectName = event.getProject().getName();
    deliverMessage(factory.createInfoMessage("Build starting for "
                   +projectName));
  }

  public void buildFinished(BuildEvent event) {
    Throwable t = event.getException();
    String projectName = event.getProject().getName();
    if (t!=null) {
      deliverMessage(factory.createErrorMessage("Build exception in "
                     +projectName+": "
                     +t.toString()));
    }
    deliverMessage(factory.createInfoMessage("Build finished for "
                   +projectName));
  }

  // ADDITIONAL METHODS NOT SHOWN
}

Refer to the source code in this article's accompanying zip file for the complete version.

Trying it Out

Assuming your syslog server is configured to accept and log UDP messages for the "local7" facility, place the above class into your classpath (or adjust your CLASSPATH system environment variable) and call Ant with the "-listener org.roblybarger.SyslogListener" argument. You will get the standard console output for your build file, and your syslog server's log files should have some new messages as well. If not, check the syslog server's configuration and restart the syslog service. Failing that, check for firewall rules causing an obstruction.

A Custom XML Logger

The BuildLogger interface in Ant is a subinterface of the BuildListener interface we have just discussed. The BuildLogger interface adds a few more methods:

setOutputPrintStream(PrintStream)
setErrorPrintStream(PrintStream)
setMessageOutputLevel(int)
setEmacsMode(boolean)

The first two pass in a PrintStream object which Ant will connect for you and which you should use in place of System.out and System.err calls. These PrintStream objects might be connected to an output file by the user at script runtime via the "-logfile" command line option, so dealing with these PrintStream objects is the right thing to do. You should save the references to some instance variables in your logger's class. The third method listed is the level of severity that the user wants messages displayed for. (The user specified this via "-v" or "-d" command line arguments.) Should you wish to honor the user's choice -- you are certainly under no obligation to do so -- you should also save this value to a instance variable and compare it to the priority level in each BuildEvent you are given later. The final method is rather curious: it signals to your logger class that the user wants output in an emacs-friendly format. (For those completely unaware, emacs is one of two very popular text-mode editors available in UNIX systems.) I'll admit mild confusion as to the utility of this method since I tend to supply do-nothing implementations for it. The Ant API is also not terribly more informative about it either.





Page 2 of 4



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel