Hi!
I've just written a wrap-around buffering appender that buffers the log messages
until an ERROR logging event happens and then forwards the buffered messages to
all its attached appenders.
I've read the thread titled "dump wrap-around buffer of all log messages"
(http://www.mail-archive.com/[email protected]/thrd7.html#09023) but
found no implementation for this idea.
Therefore I want to offer the simple code for interested people.
Here is the code:
---------------------------------------------------------
package at.sphinx.is.log4j;
import java.util.Enumeration;
import org.apache.log4j.Appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.AppenderAttachableImpl;
import org.apache.log4j.helpers.CyclicBuffer;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.AppenderAttachable;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.TriggeringEventEvaluator;
/**
* Buffers log messages in a wrap-around buffer and passes them to the attached
* appenders when a specific logging event occurs, typically on errors or fatal
errors.
*
* <p>
* The number of logging events delivered depend on the value of
<b>BufferSize</b> option.
* The <code>WrapAroundBufferAppender</code> keeps only the last
<code>BufferSize</code>
* logging events in its cyclic buffer. This keeps memory requirements at a
reasonable level
* while still delivering useful application context.
*
* @author rhandschmann
*/
public class WrapAroundBufferAppender extends AppenderSkeleton implements
AppenderAttachable
{
AppenderAttachableImpl appenderAttachableDelegate = new
AppenderAttachableImpl();
// Properties
private int bufferSize = 512;
protected CyclicBuffer cyclicBuffer = new CyclicBuffer(bufferSize);
protected TriggeringEventEvaluator evaluator;
/**
* The default constructor will instantiate the appender with a
* [EMAIL PROTECTED] TriggeringEventEvaluator} that will trigger on events
* with level ERROR or higher.
*/
public WrapAroundBufferAppender()
{
evaluator = new DefaultEvaluator();
}
/**
* Use the passed [EMAIL PROTECTED] TriggeringEventEvaluator} for this
WrapAroundBufferAppender.
*/
public WrapAroundBufferAppender(TriggeringEventEvaluator
triggeringEventEvaluator)
{
evaluator = triggeringEventEvaluator;
}
/**
* Perform specific appending actions, mainly adding the event to a cyclic
buffer and
* checking if the event triggers the buffered messages to pass to the
attached appenders.
*
* @see
org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent)
*/
protected void append(LoggingEvent event)
{
if (!checkEntryConditions()) {
return;
}
// Set the NDC and thread name for the calling thread as these
// LoggingEvent fields were not set at event creation time.
//### needed? event.getThreadName();
//### needed? event.getNDC();
cyclicBuffer.add(event);
if (evaluator.isTriggeringEvent(event)) {
sendBuffer();
}
}
/**
* This method determines if there is a sense in attempting to append.
* It checks whether there are any attached appenders.
*/
protected boolean checkEntryConditions()
{
if (!appenderAttachableDelegate.getAllAppenders().hasMoreElements()) {
errorHandler.error("No appenders attached.");
return false;
}
return true;
}
/**
* Appends all buffered messages to all attached appenders.
*/
protected void sendBuffer()
{
// Synchronizing on the buffer to ensure no new messages are added until
the buffer is emptied
synchronized (cyclicBuffer) {
int len = cyclicBuffer.length();
for (int i = 0; i < len; i++) {
LoggingEvent event = cyclicBuffer.get();
appenderAttachableDelegate.appendLoopOnAppenders(event);
}
}
// At this point the cyclicBuffer is emty
}
/* (non-Javadoc)
* @see org.apache.log4j.Appender#close()
*/
public void close()
{
this.closed = true;
}
/**
* The <code>WrapAroundBufferAppender</code> doesn't require a layout
because it
* simply passes on the logging events to its attached appenders.
*
* @see org.apache.log4j.Appender#requiresLayout()
*/
public boolean requiresLayout()
{
return false;
}
/**
* The <b>BufferSize</b> option takes a positive integer representing the
maximum number
* of logging events to collect in a cyclic buffer.
* When the <code>BufferSize</code> is reached, oldest events are deleted as
new events are
* added to the buffer. By default the size of the cyclic buffer is 512
events.
*/
public void setBufferSize(int bufferSize)
{
this.bufferSize = bufferSize;
cyclicBuffer.resize(bufferSize);
}
/**
* The <b>EvaluatorClass</b> option takes a string value representing the
name of the
* class implementing the [EMAIL PROTECTED] TriggeringEventEvaluator}
interface.
* A corresponding object will be instantiated and assigned as the
triggering event evaluator
* for the <code>WrapAroundBufferAppender</code>.
*/
public void setEvaluatorClass(String className)
{
evaluator = (TriggeringEventEvaluator)
OptionConverter.instantiateByClassName(className,
TriggeringEventEvaluator.class, evaluator);
}
//
// Implementation of the AppenderAttachable interface
//
/* (non-Javadoc)
* @see
org.apache.log4j.spi.AppenderAttachable#addAppender(org.apache.log4j.Appender)
*/
public void addAppender(Appender newAppender)
{
synchronized (appenderAttachableDelegate) {
appenderAttachableDelegate.addAppender(newAppender);
}
}
/* (non-Javadoc)
* @see org.apache.log4j.spi.AppenderAttachable#getAllAppenders()
*/
public Enumeration getAllAppenders()
{
synchronized (appenderAttachableDelegate) {
return appenderAttachableDelegate.getAllAppenders();
}
}
/* (non-Javadoc)
* @see
org.apache.log4j.spi.AppenderAttachable#getAppender(java.lang.String)
*/
public Appender getAppender(String appenderName)
{
synchronized (appenderAttachableDelegate) {
return appenderAttachableDelegate.getAppender(name);
}
}
/* (non-Javadoc)
* @see
org.apache.log4j.spi.AppenderAttachable#isAttached(org.apache.log4j.Appender)
*/
public boolean isAttached(Appender appender)
{
return appenderAttachableDelegate.isAttached(appender);
}
/* (non-Javadoc)
* @see org.apache.log4j.spi.AppenderAttachable#removeAllAppenders()
*/
public void removeAllAppenders()
{
synchronized (appenderAttachableDelegate) {
appenderAttachableDelegate.removeAllAppenders();
}
}
/* (non-Javadoc)
* @see
org.apache.log4j.spi.AppenderAttachable#removeAppender(org.apache.log4j.Appender)
*/
public void removeAppender(Appender appender)
{
synchronized (appenderAttachableDelegate) {
appenderAttachableDelegate.removeAppender(appender);
}
}
/* (non-Javadoc)
* @see
org.apache.log4j.spi.AppenderAttachable#removeAppender(java.lang.String)
*/
public void removeAppender(String appenderName)
{
synchronized (appenderAttachableDelegate) {
appenderAttachableDelegate.removeAppender(name);
}
}
static class DefaultEvaluator implements TriggeringEventEvaluator
{
/**
* Is this <code>event</code> the triggering event?
* This method returns <code>true</code>, if the event level
* has ERROR level or higher. Otherwise it returns <code>false</code>.
*/
public boolean isTriggeringEvent(LoggingEvent event)
{
return event.getLevel().isGreaterOrEqual(Level.ERROR);
}
}
}
---------------------------------------------------------
Greetings,
Robert Handschmann
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]