SlowDownSpamEvaluator
From EggeWiki
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; } }


