/* 
 * Copyright 1999,2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggingEvent;

/**
 * 
 * The TokenBucketFilter is a logging filter that uses the Token Bucket
 * algorithm to regulate logging traffic. Use this filter when you want to
 * control the maximum traffic burst of log statements that can be sent to an
 * appender. The filter is configured in the log4j configuration file. For
 * example, the following configuration limits the number of log statements that
 * can be sent to the console to a burst of 100 and allows a maximum of 10 log
 * statements to be sent to the appender every 6 seconds after that burst.<br>
 * <br>
 * 
 * <code>
 * &lt;appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"&gt;<br>
 *  &nbsp;&lt;layout class="org.apache.log4j.PatternLayout"&gt;<br>
 * 		&nbsp;&nbsp;&lt;param name="ConversionPattern" value="%-5p %d{dd-MMM-yyyy HH:mm:ss} %x %t %m%n"/&gt;<br>
 * 	&nbsp;&lt;/layout&gt;<br>
 * 	&nbsp;&lt;filter class="TokenBucketFilter"&gt;<br>
 * 		&nbsp;&nbsp;&lt;param name="tokenFillAmount" value="10"/&gt;<br>
 * 		&nbsp;&nbsp;&lt;param name="tokenFillInterval" value="6"/&gt;<br>
 * 		&nbsp;&nbsp;&lt;param name="maxTokens" value="100"/&gt;<br>
 * 	&nbsp;&lt;/filter&gt;<br>
 * &lt;/appender&gt;<br>
 * </code><br>
 * 
 * Every time a log statement is sent to an appender using this filter, the
 * filter removes a token from the bucket. If no tokens are left in the bucket
 * the log statement is suppressed. Tokens are added back to the bucket at a
 * rate of <code>tokenFillAmount</code>/<code>tokenFillInterval</code>
 * seconds up to the maximum amount of <code>maxTokens</code>.
 * 
 * @author Chad LaVigne
 * 
 */
public class TokenBucketFilter extends Filter {
  /**
   * Number of tokens to add to the token bucket. For example, a value of 10
   * means 10 tokens will be added to the bucket every
   * <code>tokenFillInterval</code> seconds.
   */
  private long tokenFillAmount;

  /**
   * Interval, in seconds, at which to add tokens to the logging filter token
   * bucket. For example, a value of 6 means <code>tokenFillAmount</code>
   * tokens will be added to the bucket every 6 seconds.
   */
  private long tokenFillInterval;

  /**
   * The maximum number of tokens the logging filter will allow in its token
   * bucket. This value dictates the maximum traffic burst that can be logged to
   * any appender that uses the <code>TokenBucketFilter</code>, i.e. there
   * can never be more than <code>maxTokens</code> log statements sent to an
   * appender in <code>tokenFillInterval</code> seconds.
   */
  private long maxTokens;

  private TokenBucket tokenBucket;

  public int decide(LoggingEvent event) {
    // initialize tokenBucket here because the tokenFillAmount,
    // tokenFillInterval & maxTokens attributes get set
    // via log4J configuration when it instantiates the filter
    if (tokenBucket == null) {
      tokenBucket = new TokenBucket(tokenFillAmount, tokenFillInterval,
          maxTokens);
    }

    return tokenBucket.getToken() ? Filter.DENY : Filter.NEUTRAL;
  }

  public long getMaxTokens() {
    return maxTokens;
  }

  public void setMaxTokens(long maxTokens) {
    this.maxTokens = maxTokens;
  }

  public long getTokenFillInterval() {
    return tokenFillInterval;
  }

  public void setTokenFillInterval(long tokenFillInterval) {
    this.tokenFillInterval = tokenFillInterval;
  }

  public long getTokenFillAmount() {
    return tokenFillAmount;
  }

  public void setTokenFillAmount(long tokenFillRate) {
    this.tokenFillAmount = tokenFillRate;
  }
}