SlowDownSpamEvaluator

From EggeWiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

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.

<geshi lang="java5"> 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(); } } </geshi>

And of course the test case. <geshi lang="java5"> 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; }

} </geshi>