| from __future__ import with_statement |
| from time import time |
| from contextlib import contextmanager |
| from pylons import request |
| |
| class StatsRecord(object): |
| |
| def __init__(self, request, active): |
| self.timers = dict( |
| mongo=0, |
| template=0, |
| total=0) |
| self.url = request.environ['PATH_INFO'] |
| self.active = active |
| # Avoid double-timing things |
| self._now_timing = set() |
| |
| def __repr__(self): |
| stats = ' '.join( |
| ('%s=%.0fms' % (k,v*1000)) |
| for k,v in sorted(self.timers.iteritems())) |
| return '%s: %s' % (self.url, stats) |
| |
| def asdict(self): |
| return dict( |
| url=self.url, |
| timers=self.timers) |
| |
| @contextmanager |
| def timing(self, name): |
| if self.active and name not in self._now_timing: |
| self._now_timing.add(name) |
| self.timers.setdefault(name, 0) |
| begin = time() |
| try: |
| yield |
| finally: |
| end = time() |
| self.timers[name] += end-begin |
| self._now_timing.remove(name) |
| else: |
| yield |
| |
| class timing(object): |
| '''Decorator to time a method call''' |
| |
| def __init__(self, timer): |
| self.timer = timer |
| |
| def __call__(self, func): |
| def inner(*l, **kw): |
| try: |
| stats = request.environ['sf.stats'] |
| except TypeError: |
| return func(*l, **kw) |
| with stats.timing(self.timer): |
| return func(*l, **kw) |
| inner.__name__ = func.__name__ |
| return inner |
| |
| def decorate(self, obj, names): |
| names = names.split() |
| for name in names: |
| setattr(obj, name, |
| self(getattr(obj, name))) |