Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2a6ec64
Showing
7 changed files
with
180 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
Introduction | ||
============ | ||
|
||
`django_statsd` is a middleware that uses `python-statsd` to log query | ||
and view durations to statsd. | ||
|
||
* Python Statsd | ||
- https://github.com/WoLpH/python-statsd | ||
* Graphite | ||
- http://graphite.wikidot.com | ||
* Statsd | ||
- code: https://github.com/etsy/statsd | ||
- blog post: http://codeascraft.etsy.com/2011/02/15/measure-anything-measure-everything/ | ||
|
||
|
||
Install | ||
======= | ||
|
||
To install simply execute `python setup.py install`. | ||
If you want to run the tests first, run `python setup.py nosetests` | ||
|
||
|
||
Usage | ||
===== | ||
|
||
Just add `django_statsd` to the `installed_apps` and add | ||
`django_statsd.middleware.TimingMiddleware` to `MIDDLEWARE_CLASSES` | ||
|
||
|
||
Advanced Usage | ||
-------------- | ||
|
||
>>> def some_view(request): | ||
... with request.timings('something_to_time'): | ||
... # do something here | ||
... pass | ||
>>> | ||
>>> def some_view(request): | ||
... request.timings.start('something_to_time') | ||
... # do something here | ||
... request.timings.stop('something_to_time') | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from __future__ import with_statement | ||
import time | ||
from django_statsd import utils | ||
import logging | ||
import threading | ||
logger = logging.getLogger(__name__) | ||
|
||
class WithTimer(object): | ||
def __init__(self, timer, key): | ||
self.timer = timer | ||
self.key = key | ||
|
||
def __enter__(self): | ||
self.timer.start(self.key) | ||
|
||
def __exit__(self, type_, value, traceback): | ||
self.timer.stop(self.key) | ||
|
||
|
||
class Timer(object): | ||
def __init__(self): | ||
self.starts = {} | ||
self.totals = {} | ||
|
||
def start(self, key): | ||
assert key not in self.starts, 'Already started tracking %s' % key | ||
self.starts[key] = time.time() | ||
|
||
def stop(self, key): | ||
assert ( | ||
key in self.starts, | ||
'Unable to stop tracking %s, never started tracking it' % key, | ||
) | ||
|
||
delta = time.time() - self.starts.pop(key) | ||
self.totals[key] = self.totals.get(key, 0.0) + delta | ||
return delta | ||
|
||
def submit(self, request_method, view_name): | ||
prefix = 'view.%s.%s' % (request_method, view_name) | ||
|
||
timer = utils.get_timer(prefix) | ||
|
||
for k in self.totals.keys(): | ||
timer.send(k, self.totals.pop(k)) | ||
|
||
def __call__(self, key): | ||
return WithTimer(self, key) | ||
|
||
|
||
class TimingMiddleware(object): | ||
scope = threading.local() | ||
|
||
def process_request(self, request): | ||
# store the timings in the request so it can be used everywhere | ||
request.timings = Timer() | ||
request.timings.start('total') | ||
self.scope = request | ||
self.view_name = None | ||
|
||
def process_view(self, request, view_func, view_args, view_kwargs): | ||
# View name is defined as module.view | ||
# (e.g. django.contrib.auth.views.login) | ||
self.view_name = view_func.__module__ + '.' + view_func.__name__ | ||
|
||
# Time the response | ||
with request.timings('view'): | ||
response = view_func(request, *view_args, **view_kwargs) | ||
|
||
return response | ||
|
||
def process_response(self, request, response): | ||
request.timings.stop('total') | ||
if self.view_name: | ||
request.timings.submit( | ||
request.method.lower(), | ||
self.view_name, | ||
) | ||
|
||
return response | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from django_statsd import utils | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import statsd | ||
from django.conf import settings | ||
|
||
def get_connection(host=None, port=None, sample_rate=None): | ||
if not host: | ||
host = getattr(settings, 'STATSD_HOST', '127.0.0.1') | ||
|
||
if not port: | ||
port = getattr(settings, 'STATSD_PORT', 8125) | ||
|
||
if not sample_rate: | ||
sample_rate = getattr(settings, 'STATSD_SAMPLE_RATE', 1.0) | ||
|
||
return statsd.Connection(host, port, sample_rate) | ||
|
||
def get_timer(name, connection=None): | ||
if not connection: | ||
connection = get_connection() | ||
|
||
return statsd.Timer(name, connection) | ||
|
||
def get_client(name, connection=None): | ||
if not connection: | ||
connection = get_connection() | ||
|
||
return statsd.Client(name, connection) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[nosetests] | ||
verbosity=3 | ||
with-doctest=1 | ||
detailed-errors=1 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import os | ||
from setuptools import setup | ||
|
||
def read(fname): | ||
return open(os.path.join(os.path.dirname(__file__), fname)).read() | ||
|
||
setup( | ||
name = 'django-statsd', | ||
version = '1.0', | ||
author = 'Rick van Hattem', | ||
author_email = 'Rick.van.Hattem@Fawo.nl', | ||
description = '''django-statsd is a django app that submits query and | ||
view durations to Etsy's statsd.''', | ||
url='https://github.com/WoLpH/django-statsd', | ||
license = 'BSD', | ||
packages=['django_statsd'], | ||
long_description=read('README.rst'), | ||
test_suite='nose.collector', | ||
setup_requires=['nose'], | ||
classifiers=[ | ||
'License :: OSI Approved :: BSD License', | ||
], | ||
) |