SlowDownSpamEvaluator

From EggeWiki

Jump to: navigation, search

Occasionally something will go wrong in a program an log4j will send a mountain of emails. Here's a simple filtering class that can be used to prevent too many emails from being sent at once.

import java.util.LinkedList;
 
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.TriggeringEventEvaluator;
/**
 * This class is a filter for log4j to send at most four emails per hour.
 * @author brianegge
 */
public class SlowDownSpamEvaluator implements TriggeringEventEvaluator {
 
	private static final int MAX_MESSAGES_PER_HOUR = 4;
	private final LinkedList queue = new LinkedList();
	private final TriggeringEventEvaluator parent;
 
	public SlowDownSpamEvaluator() {
		parent = null;
	}
 
	public SlowDownSpamEvaluator(TriggeringEventEvaluator parent) {
		this.parent = parent;
	}
 
	/**
	 * At most, {@value #MAX_MESSAGES_PER_HOUR} messages per hour will be triggered. 
	 * @return Is this the triggering event?
	 */
	public boolean isTriggeringEvent(LoggingEvent event) {
		long oneHourAgo = getTime() - 1000L * 60 * 60;
		synchronized (queue) {
			while(queue.size() > 0 && ((Long)queue.getLast()).longValue() <= oneHourAgo)
				queue.removeLast();
			if (queue.size() >= MAX_MESSAGES_PER_HOUR) { // we've sent more than four messages in the past hour
				return false;
			}
			queue.addFirst(new Long(getTime()));
		}
		if (parent != null) 
			return parent.isTriggeringEvent(event);
		return true;
	}
 
	/**
	 * subclasses can override this method for testing.  <a href="http://joda-time.sourceforge.net/">
	 * Joda Time</a> provides good testing capabilities,
	 * but I don't want to add an external dependency.
	 * 
	 * @return System.currentTimeMillis()
	 */
	protected long getTime() {
		return System.currentTimeMillis();
	}
}

And of course the test case.

import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.TriggeringEventEvaluator;
 
import junit.framework.TestCase;
 
public class SlowDownSpamEvaluatorUnitTest extends TestCase implements TriggeringEventEvaluator {
 
	int parent;
	long offset;
 
	public void testIsTriggeringEvent() {
		TriggeringEventEvaluator evaluator = new SlowDownSpamEvaluator() {
			protected long getTime() {
				return super.getTime() + offset;
			}
		};
		assertTrue(evaluator.isTriggeringEvent(null));
		assertTrue(evaluator.isTriggeringEvent(null));
		assertTrue(evaluator.isTriggeringEvent(null));
		assertTrue(evaluator.isTriggeringEvent(null));
		assertFalse(evaluator.isTriggeringEvent(null));
		offset += 1000L * 60 * 60; // One hour
		assertTrue(evaluator.isTriggeringEvent(null));
	}
 
	public void testParent() throws Exception {
		TriggeringEventEvaluator evaluator = new SlowDownSpamEvaluator(this);
		assertEquals(0, parent);
		assertFalse(evaluator.isTriggeringEvent(null));
		assertEquals(1, parent);
	}
 
	// we could use EasyMock, but since this is a small project, I'll create the stub in-line
	public boolean isTriggeringEvent(LoggingEvent event) {
		parent++;
		return false;
	}
 
}
Personal tools
Travelling Salesman

Get the app!