Writing to Xindice with Log4J Appender

by Jim Fuller jim.fuller@ruminate.co.uk Jan 12th, 2004

Log4j allows logging requests to be piped to multiple destinations. A log4j output is known as an appender. Log4j provides a slew of appenders writing to the console, files, remote socket servers, JMS, NT Event Loggers, remote UNIX Syslog daemons, etc... . An appender is linked to a logger through either calling configuration API or defining a seperate property file. In addition, you can define the layout of an event; e.g. I have been using the XML Layout option for awhile now ( even though I really need to hack out the use of CDATA ) and I wondered how easy it would be to pipe all log4j events to be written into Xindice.

I wanted to be able to change all my existing log property files to use a new Appender called XindiceAppender, which meant that all logs would be placed within an Xindice db collection. I also needed to have a file written everytime for backup purposes.

For demonstration of the technique I will hack up the addDocument.java example that comes with the xindice documentation. Note that I just place this in a package called com.example.xindice So firstly we need to have an object that takes care of the writing to Xindice.

addDocument.java

package com.example.xindice;

import org.xmldb.api.base.*; import org.xmldb.api.modules.*; import org.xmldb.api.*;

import java.lang.RuntimeException;

import java.io.*;

public class addDocument {

{{{ /**

{{{ /**

{{{ /**

{{{ /**

{{{ public void setEvent(String event) {

//because our methods throws exceptions and subAppend doesnt we hack our way through with unchecked exceptions public void writeEvent() throws RuntimeException {

   try { 

    }catch(Exception e){ 

    } 

public static void write(String event, String collection, String namespace) throws Exception {

{{{ Collection col = null;

}

}

The write method does all the heavy lifting, with the entry point for the logger to use writeEvent. There are set methods for prescribing the event, namespace to use for logger xml, and collection path.

We have had to use unchecked exceptions because of log4j architecture, this is simply through desire to illustrate things simply here. As you will see in the Appender description, we subclass from the log4j Appender class, which would have needed modification to handle our exception events properly.

The next file is the actual appender, its just a hacked up version of WriterAppender.java that comes with log4j.

XindiceAppender.java

package com.example.xindice;

import java.io.IOException; import java.io.Writer; import java.io.FileOutputStream; import java.io.BufferedWriter;

import org.apache.log4j.*; import org.apache.log4j.spi.ErrorCode; import org.apache.log4j.helpers.QuietWriter; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent;

import com.example.addDocument;

// XindiceWriter is based on modified WriterAppender code // Author: Jim Fuller <jim.fuller@ruminate.co.uk> // // Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de> // Ben Sandee

/** {{{ * XindiceAppender appends log events to a file and to an Xindice instantiation.

public class XindiceAppender extends WriterAppender {

{{{ /** Append to or truncate the file? The default value for this

/** {{{ instantiate com.epinx.xindice.addDocument object. */

{{{ this.layout = layout;

{{{ }

{{{ }

{{{ }

{{{ }

{{{ if(layout.ignoresThrowable()) {

}

I have added a few flags and vars that handle the extra requirements of writing to Xindice.

The following flags just control behavior

- writeXindice: if set to yes will write event to xindice - writeFile: if set to yes will also write event to file

The Collection, log4jNamespace define respectively the db collection path and namespace to use in the generated event xml.

Basically XindiceAppender should work in the same manner as WriterAppender with the added benefit of writing to xindice. So lets now show an example property configuration file; I tend to use the xml version.

property.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> {{{ <appender name="myAppender" class="com.example.xindice.XindiceAppender">

</log4j:configuration>

The com.example.xindice.XindiceAppender appender should write to whatever collection you have defined in xindice.

Note that each event gets written as a single document within xindice, and since I have ommited explicitly naming the documents...I settled for xindice's method of automatically naming a file.

Without testing there will perhaps be conflicts with Xindice's own usage of Log4j, in addition it remains to be seen if xindice can handle such high volume, small transaction type data handling.

Improvements for the future could be;

- prescribe xindice xml document name - append option to append to existing file - add additional xml meta data - add xslt interception

good luck, Jim Fuller

JXindiceAppender (last edited 2009-09-20 23:33:31 by localhost)