mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-04-27 03:00:12 -04:00
Record VRatelimit metrics
With these metrics, we'll be able to see the number of times: 1. We set a user-based limit 2. We set an ip-based limit 3. A user is exempted from ratelimit checks 4. We check a user-based limit 5. We check an ip-based limit 6. A user-based limit is hit 7. An ip-based limit is hit Dealing with sampling rates is a little bit tricky, since we're recording per-prefix and some endpoints are hit much more frequently than others. I did a simplistic grep to get the endpoints that use `VRatelimit`, then took a look at the rate of requests for all of those; it looks like a 10% sampling rate shouldn't overwhelm our graphite servers on the popular endpoints, and won't be *awful* for the infrequently-requested ones (as long as we look at long time periods for them).
This commit is contained in:
@@ -1844,7 +1844,7 @@ class VRatelimit(Validator):
|
||||
self.seconds = None
|
||||
Validator.__init__(self, *a, **kw)
|
||||
|
||||
def run (self):
|
||||
def run(self):
|
||||
if g.disable_ratelimit:
|
||||
return
|
||||
|
||||
@@ -1852,13 +1852,16 @@ class VRatelimit(Validator):
|
||||
hook = hooks.get_hook("account.is_ratelimit_exempt")
|
||||
ratelimit_exempt = hook.call_until_return(account=c.user)
|
||||
if ratelimit_exempt:
|
||||
self._record_event(self.prefix, 'exempted')
|
||||
return
|
||||
|
||||
to_check = []
|
||||
if self.rate_user and c.user_is_loggedin:
|
||||
to_check.append('user' + str(c.user._id36))
|
||||
self._record_event(self.prefix, 'check_user')
|
||||
if self.rate_ip:
|
||||
to_check.append('ip' + str(request.ip))
|
||||
self._record_event(self.prefix, 'check_ip')
|
||||
|
||||
r = g.cache.get_multi(to_check, self.prefix)
|
||||
if r:
|
||||
@@ -1866,6 +1869,11 @@ class VRatelimit(Validator):
|
||||
time = utils.timeuntil(expire_time)
|
||||
|
||||
g.log.debug("rate-limiting %s from %s" % (self.prefix, r.keys()))
|
||||
for key in r.keys():
|
||||
if key.startswith('user'):
|
||||
self._record_event(self.prefix, 'user_limit_hit')
|
||||
elif key.startswith('ip'):
|
||||
self._record_event(self.prefix, 'ip_limit_hit')
|
||||
|
||||
# when errors have associated field parameters, we'll need
|
||||
# to add that here
|
||||
@@ -1881,7 +1889,7 @@ class VRatelimit(Validator):
|
||||
self.set_error(self.error)
|
||||
|
||||
@classmethod
|
||||
def ratelimit(self, rate_user = False, rate_ip = False, prefix = "rate_",
|
||||
def ratelimit(cls, rate_user = False, rate_ip = False, prefix = "rate_",
|
||||
seconds = None):
|
||||
to_set = {}
|
||||
if seconds is None:
|
||||
@@ -1889,10 +1897,16 @@ class VRatelimit(Validator):
|
||||
expire_time = datetime.now(g.tz) + timedelta(seconds = seconds)
|
||||
if rate_user and c.user_is_loggedin:
|
||||
to_set['user' + str(c.user._id36)] = expire_time
|
||||
cls._record_event(prefix, 'set_user_limit')
|
||||
if rate_ip:
|
||||
to_set['ip' + str(request.ip)] = expire_time
|
||||
cls._record_event(prefix, 'set_ip_limit')
|
||||
g.cache.set_multi(to_set, prefix = prefix, time = seconds)
|
||||
|
||||
@classmethod
|
||||
def _record_event(cls, prefix, event):
|
||||
g.stats.event_count('VRatelimit.%s' % prefix, event, sample_rate=0.1)
|
||||
|
||||
|
||||
class VCommentIDs(Validator):
|
||||
def run(self, id_str):
|
||||
|
||||
Reference in New Issue
Block a user