Class RateLimitStatus


  • public abstract class RateLimitStatus
    extends Object
    Status for rate limiting operations, usable by rate limiters and available to subclasses of LogContext to handle rate limiting consistently.

    Design Notes

    The purpose of this class is to allow rate limiters to behave in a way which is consistent when multiple rate limiters are combined for a single log statement. If you are writing a rate limiter for Flogger which you want to "play well" with other rate limiters, it is essential that you understand how RateLimitStatus is designed to work.

    Firstly, LogContext tracks a single status for each log statement reached. This is modified by code in the postProcess() method (which can be overridden by custom logger implementations).

    When a rate limiter is used, it returns a RateLimitStatus, which is combined with the existing value held in the context:

    
     rateLimitStatus = RateLimitStatus.combine(rateLimitStatus, MyCustomRateLimiter.check(...));
     >/pre>
    
     

    A rate limiter should switch between two primary states "limiting" and "pending":

    • In the "limiting" state, the limiter should return the DISALLOW value and update any internal state until it reaches its trigger condition. Once the trigger condition is reached, the limiter enters the "pending" state.
    • In the "pending" state, the limiter returns an "allow" status until it is reset().

    This two-step approach means that, when multiple rate limiters are active for a single log statement, logging occurs after all rate limiters are "pending" (and at this point they are all reset). This is much more consistent than having each rate limiter operate independently, and allows a much more intuitive understanding of expected behaviour.

    It is recommended that most rate limiters should start in the "pending" state to ensure that the first log statement they process is emitted (even when multiple rate limiters are used). This isn't required, but it should be documented either way.

    Each rate limiter is expected to follow this basic structure:

    {@code
     final class CustomRateLimiter extends RateLimitStatus {
       private static final LogSiteMap map =
           new LogSiteMap() {
    See Also:
    Original Java code of Google Flogger
    • Field Summary

      Fields 
      Modifier and Type Field Description
      static RateLimitStatus ALLOW
      The status to return whenever a stateless rate limiter determines that logging should occur.
      static RateLimitStatus DISALLOW
      The status to return whenever a rate limiter determines that logging should not occur.
    • Constructor Summary

      Constructors 
      Modifier Constructor Description
      protected RateLimitStatus()
      Rate limiters can extend this class directly if their "reset" operation is stateless, or they can create and return new instances to capture any necessary state.
    • Field Detail

      • DISALLOW

        public static final RateLimitStatus DISALLOW
        The status to return whenever a rate limiter determines that logging should not occur.

        All other statuses implicity "allow" logging.

      • ALLOW

        public static final RateLimitStatus ALLOW
        The status to return whenever a stateless rate limiter determines that logging should occur.

        Note: Truly stateless rate limiters should be very rare, since they cannot hold onto a pending "allow" state. Even a simple "sampling rate limiter" should be stateful if once the "allow" state is reached it continues to be returned until logging actually occurs.

    • Constructor Detail

      • RateLimitStatus

        protected RateLimitStatus()
        Rate limiters can extend this class directly if their "reset" operation is stateless, or they can create and return new instances to capture any necessary state.
    • Method Detail

      • reset

        protected abstract void reset()
        Resets an associated rate limiter, moving it out of the "pending" state and back into rate limiting mode.

        Note: This method is never invoked concurrently with another reset() operation, but it can be concurrent with calls to update rate limiter state. Thus it must be thread safe in general, but can assume it's the only reset operation active for the limiter which returned it.