diff options
author | Luke Shumaker <LukeShu@sbcglobal.net> | 2013-04-21 02:22:44 -0400 |
---|---|---|
committer | Luke Shumaker <LukeShu@sbcglobal.net> | 2013-04-21 02:22:44 -0400 |
commit | 03fa7e4f27bdb39a8f8f5ed91a87d18bf8357b47 (patch) | |
tree | c67eafcbda55706f18400b3115a2b8a5be318394 /main/log.py | |
parent | 91c451821ce7000cbc268cec8427d208a6cedd7e (diff) | |
parent | b8ee7b1ee281b45b245fb454228b8ad847c56200 (diff) |
Merge branch 'archweb' into archweb-generic2
Conflicts:
devel/views.py
feeds.py
public/views.py
settings.py
sitestatic/archweb.js
templates/base.html
templates/devel/profile.html
templates/mirrors/status.html
templates/news/view.html
templates/packages/flaghelp.html
templates/packages/opensearch.xml
templates/public/download.html
templates/public/feeds.html
templates/public/index.html
templates/registration/login.html
templates/releng/results.html
templates/todolists/public_list.html
Diffstat (limited to 'main/log.py')
-rw-r--r-- | main/log.py | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/main/log.py b/main/log.py new file mode 100644 index 00000000..63634874 --- /dev/null +++ b/main/log.py @@ -0,0 +1,71 @@ +# Derived from Django snippets: http://djangosnippets.org/snippets/2242/ +from collections import OrderedDict +from datetime import datetime, timedelta +from hashlib import md5 +import traceback +from pytz import utc + + +class LimitedSizeDict(OrderedDict): + def __init__(self, *args, **kwargs): + self.size_limit = kwargs.pop('size', None) + if self.size_limit == 0: + self.size_limit = None + if self.size_limit and self.size_limit < 0: + raise Exception('Invalid size specified') + super(LimitedSizeDict, self).__init__(*args, **kwargs) + self.check_item_limits() + + def __setitem__(self, key, value): + # delete and add to ensure it ends up at the end of the linked list + if key in self: + super(LimitedSizeDict, self).__delitem__(key) + super(LimitedSizeDict, self).__setitem__(key, value) + self.check_item_limits() + + def check_item_limits(self): + if self.size_limit is None: + return + while len(self) > self.size_limit: + self.popitem(last=False) + + +class RateLimitFilter(object): + def __init__(self, name='', rate=10, prefix='error_rate', max_keys=100): + # delayed import otherwise we have a circular dep when setting up + # the logging config: settings -> logging -> cache -> settings + self.cache_module = __import__('django.core.cache', fromlist=['cache']) + self.errors = LimitedSizeDict(size=max_keys) + self.rate = rate + self.prefix = prefix + + def filter(self, record): + if self.rate == 0: + # rate == 0 means totally unfiltered + return True + + trace = '\n'.join(traceback.format_exception(*record.exc_info)) + key = md5(trace).hexdigest() + duplicate = False + cache = self.cache_module.cache + + # Test if the cache works + try: + cache.set(self.prefix, 1, 300) + use_cache = (cache.get(self.prefix) == 1) + except: + use_cache = False + + if use_cache: + cache_key = '%s_%s' % (self.prefix, key) + duplicate = (cache.get(cache_key) == 1) + cache.set(cache_key, 1, self.rate) + else: + now = datetime.utcnow().replace(tzinfo=utc) + min_date = now - timedelta(seconds=self.rate) + duplicate = (key in self.errors and self.errors[key] >= min_date) + self.errors[key] = now + + return not duplicate + +# vim: set ts=4 sw=4 et: |