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:
xiongchiamiov
2015-05-19 16:06:10 -07:00
parent 4222697f8c
commit 0df5ed1859

View File

@@ -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):