Git Product home page Git Product logo

ratelimitingfilter's Introduction

RateLimitingFilter

image

image

image

image

image

The RateLimitingFilter is a filter for the Python logging system that allows you to restrict the rate at which messages can pass through your logging handlers.

The filter can be useful if you're using a handler such as Python's logging.handlers.SMTPHandler to send error notification emails. Error notification emails provide a useful means of keeping an eye on the health of a running system, but these emails have the potential to overload a mailbox if they start arriving in quick succession due to some kind of critical failure.

The RateLimitingFilter can help prevent mailbox overload by throttling messages based on a configurable rate, whilst allowing for periodic bursts of messages which can be a useful indicator that something somewhere has broken.

Compatibility

  • Python 2.7, 3.4+

Installing

$ pip install ratelimitingfilter

or

$ git clone https://github.com/wkeeling/ratelimitingfilter.git
$ cd ratelimitingfilter
$ python setup.py install

Usage

You can rate-limit a logging handler simply by creating a new instance of the RateLimitingFilter and adding it to the handler:

from ratelimitingfilter import RateLimitingFilter

...

ratelimit = RateLimitingFilter()
handler.addFilter(ratelimit)

Creating an instance of the RateLimitingFilter without any arguments like in the example above will restrict the flow of messages to 1 every 30 seconds.

You can customize the flow rate by supplying your own values for the rate, per and burst attributes. For example, to allow a rate of 1 message every 2 minutes with a periodic burst of up to 5 messages:

ratelimit = RateLimitingFilter(rate=1, per=120, burst=5)
handler.addFilter(ratelimit)

SMTPHandler Example

A typical use case may be to throttle error notification emails sent by the logging.handlers.SMTPHandler.

Here's an example of how you might set that up:

import logging.handlers
import time

from ratelimitingfilter import RateLimitingFilter

logger = logging.getLogger('throttled_smtp_example')

# Create an SMTPHandler
smtp = logging.handlers.SMTPHandler(
    mailhost='smtp.example.com',
    fromaddr='[email protected]',
    toaddrs='[email protected]',
    subject='An error has occurred'
)
smtp.setLevel(logging.ERROR)

# Create a formatter and set it on the handler
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
smtp.setFormatter(formatter)

# Create an instance of the RateLimitingFilter, and add it to the handler
ratelimit = RateLimitingFilter()
smtp.addFilter(ratelimit)

# Add the handler to the logger
logger.addHandler(smtp)

# Logged errors will now be restricted to 1 every 30 seconds
while True:
    logger.error('An error message')
    time.sleep(2)

Advanced Usage

It is possible to pass some additional configuration options to the RateLimitingFilter initializer for further control over message throttling.

Perhaps you want to selectively throttle particular error messages whilst allowing other messages to pass through freely. This might be the case if there is part of the application which you know can generate large volumes of errors, whilst the rest of the application is unlikely to.

One way to achieve this might be to use separate loggers, one configured with rate limiting, one without, for the different parts of the application. Alternatively, you can use a single logger and configure the RateLimitingFilter to match only those messages that you want to throttle.

Applying selective rate limiting allows for constant visbility of lower volume errors whilst keeping the higher volume errors in check.

The RateLimitingFilter supports two ways to selectively throttle messages:

Substring based message throttling

You can pass a list of substrings to the RateLimitingFilter which it will use to match messages to apply to.

config = {'match': ['some error', 'a different error']}

ratelimit = RateLimitingFilter(rate=1, per=60, burst=1, **config)
smtp.addFilter(ratelimit)

# Can be rate limited
logger.error('some error occurred')

# Can be rate limited
logger.error('a different error occurred')

# Will not be rate limited
logger.error('something completely different happened')

Automatic message throttling

This is an experimental feature.

You can let the RateLimitingFilter automatically throttle messages by setting the match option to auto.

config = {'match': 'auto'}
ratelimit = RateLimitingFilter(rate=1, per=60, burst=1, **config)

The filter will then attempt to identify messages based on their content in order to figure out whether to throttle them or not. It will tolerate slight differences in content when identifying messages. So for example, if error messages are being rapidly logged that are the same apart from a timestamp, or perhaps an incrementing id, then these messages will be treated as the same as far as rate limiting is concerned.

License

MIT

Contributing

Feedback and improvements are more than welcome. Please submit a pull request!

https://github.com/wkeeling/ratelimitingfilter

ratelimitingfilter's People

Contributors

donkirkby avatar michel-slm avatar pstoll avatar saimecs avatar wkeeling avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ratelimitingfilter's Issues

Only once messages

Hi,

Nice library! I'm looking a way to setup a throttling that passes a record only once. Is it possible with your filters?

ratelimitingfitler is now part of Fedora

Hey,
I've build an RPM package out of this repository for Fedora.

It is currently available in Fedora 27, Fedora 28, and Rawhide.

You can install with:
dnf install python{2,3}-ratelimitingfilter

BUG: record.msg is being rendered without clearing args

record.msg = '{msg}{linesep}... {num} additional messages suppressed'.format(

By using getMessage(), you are omitting any formatting parameter, this will cause an issue when the logger uses args

For example: logger.info("Example: %s", "text") will be rendered twice while the second time it will be something similar to
"Example: text" % ("text",)

In order to fix this, you only need to set record.args to an empty tuple

Missing from pypi

This looks like a useful library. Would you be willing to put it on pypi?

TypeError: unsupported operand type(s) for +=: 'int' and 'str'

Hey,
When logging just an numeric value, and rate limiting kicks in, a TypeError is raised, as the library tries to concatenate an int and str.

eg.

for x in range(100):
    log.info(x)
  File "/home/mnuttall/.pyenv/versions/3.6.5/lib/python3.6/logging/__init__.py", line 718, in filter
    result = f.filter(record)
  File "/home/mnuttall/.local/share/virtualenvs/catalog-ilphx365/lib/python3.6/site-packages/ratelimitingfilter/ratelimitingfilter.py", line 74, in filter
    num=bucket.limited)
TypeError: unsupported operand type(s) for +=: 'int' and 'str'

Otherwise, thanks for the lib ๐Ÿ‘

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.