added a metlog backend for django-statsd (issue #11)

This commit is contained in:
Victor Ng 2012-09-10 19:22:58 -04:00
parent 7286074273
commit 34047e50e6
7 changed files with 167 additions and 4 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
*.py[co]
build
dist

View File

@ -2,7 +2,7 @@ language: python
python:
- "2.6"
- "2.7"
install: pip install -r requirements.txt --use-mirrors
install: pip install -r requirements.txt -r optional.txt --use-mirrors
script: nosetests
notifications:
irc: "irc.mozilla.org#amo-bots"

View File

@ -0,0 +1,26 @@
from statsd.client import StatsClient
from django.conf import settings
class StatsClient(StatsClient):
"""A client that pushes messages to metlog """
def __init__(self, *args, **kw):
super(StatsClient, self).__init__(*args, **kw)
if getattr(settings, 'METLOG', None) is None:
raise AttributeError(
"Metlog needs to be configured as settings.METLOG")
self.metlog = settings.METLOG
def timing(self, stat, delta, rate=1):
"""Send new timing information. `delta` is in milliseconds."""
self.metlog.timer_send(stat, delta, rate=rate)
def incr(self, stat, count=1, rate=1):
"""Increment a stat by `count`."""
self.metlog.incr(stat, count, rate=rate)
def decr(self, stat, count=1, rate=1):
"""Decrement a stat by `count`."""
self.metlog.incr(stat, -count, rate=rate)

0
django_statsd/mydatabase Normal file
View File

View File

@ -1,7 +1,10 @@
import json
import logging
import sys
from django.conf import settings
from nose.exc import SkipTest
from nose import tools as nose_tools
minimal = {
'DATABASES': {
@ -10,8 +13,9 @@ minimal = {
'NAME': 'mydatabase'
}
},
'ROOT_URLCONF':'',
'STATSD_CLIENT': 'django_statsd.clients.null'
'ROOT_URLCONF': '',
'STATSD_CLIENT': 'django_statsd.clients.null',
'METLOG': None
}
if not settings.configured:
@ -45,7 +49,6 @@ cfg = {
}
@mock.patch.object(middleware.statsd, 'incr')
class TestIncr(TestCase):
@ -135,6 +138,129 @@ class TestClient(unittest.TestCase):
eq_(client.cache, {'testing|count': [[1, 1]]})
class TestMetlogClient(unittest.TestCase):
def check_metlog(self):
try:
from metlog.config import client_from_dict_config
return client_from_dict_config
except ImportError:
raise SkipTest("Metlog is not installed")
@nose_tools.raises(AttributeError)
def test_no_metlog(self):
with mock.patch.object(settings, 'STATSD_CLIENT',
'django_statsd.clients.moz_metlog'):
get_client()
def test_get_client(self):
client_from_dict_config = self.check_metlog()
METLOG_CONF = {
'logger': 'django-statsd',
'sender': {
'class': 'metlog.senders.DebugCaptureSender',
},
}
metlog = client_from_dict_config(METLOG_CONF)
with mock.patch.object(settings, 'METLOG', metlog):
with mock.patch.object(settings, 'STATSD_CLIENT',
'django_statsd.clients.moz_metlog'):
client = get_client()
eq_(client.__module__, 'django_statsd.clients.moz_metlog')
def test_metlog_incr(self):
client_from_dict_config = self.check_metlog()
# Need to load within the test in case metlog is not installed
from metlog.config import client_from_dict_config
METLOG_CONF = {
'logger': 'django-statsd',
'sender': {
'class': 'metlog.senders.DebugCaptureSender',
},
}
metlog = client_from_dict_config(METLOG_CONF)
with mock.patch.object(settings, 'METLOG', metlog):
with mock.patch.object(settings, 'STATSD_CLIENT',
'django_statsd.clients.moz_metlog'):
client = get_client()
eq_(len(client.metlog.sender.msgs), 0)
client.incr('testing')
eq_(len(client.metlog.sender.msgs), 1)
msg = json.loads(client.metlog.sender.msgs[0])
eq_(msg['severity'], 6)
eq_(msg['payload'], '1')
eq_(msg['fields']['rate'], 1)
eq_(msg['fields']['name'], 'testing')
eq_(msg['type'], 'counter')
def test_metlog_decr(self):
client_from_dict_config = self.check_metlog()
# Need to load within the test in case metlog is not installed
from metlog.config import client_from_dict_config
METLOG_CONF = {
'logger': 'django-statsd',
'sender': {
'class': 'metlog.senders.DebugCaptureSender',
},
}
metlog = client_from_dict_config(METLOG_CONF)
with mock.patch.object(settings, 'METLOG', metlog):
with mock.patch.object(settings, 'STATSD_CLIENT',
'django_statsd.clients.moz_metlog'):
client = get_client()
eq_(len(client.metlog.sender.msgs), 0)
client.decr('testing')
eq_(len(client.metlog.sender.msgs), 1)
msg = json.loads(client.metlog.sender.msgs[0])
eq_(msg['severity'], 6)
eq_(msg['payload'], '-1')
eq_(msg['fields']['rate'], 1)
eq_(msg['fields']['name'], 'testing')
eq_(msg['type'], 'counter')
def test_metlog_timing(self):
client_from_dict_config = self.check_metlog()
# Need to load within the test in case metlog is not installed
from metlog.config import client_from_dict_config
METLOG_CONF = {
'logger': 'django-statsd',
'sender': {
'class': 'metlog.senders.DebugCaptureSender',
},
}
metlog = client_from_dict_config(METLOG_CONF)
with mock.patch.object(settings, 'METLOG', metlog):
with mock.patch.object(settings, 'STATSD_CLIENT',
'django_statsd.clients.moz_metlog'):
client = get_client()
eq_(len(client.metlog.sender.msgs), 0)
client.timing('testing', 512, rate=2)
eq_(len(client.metlog.sender.msgs), 1)
msg = json.loads(client.metlog.sender.msgs[0])
eq_(msg['severity'], 6)
eq_(msg['payload'], '512')
eq_(msg['fields']['rate'], 2)
eq_(msg['fields']['name'], 'testing')
eq_(msg['type'], 'timer')
# This is primarily for Zamboni, which loads in the custom middleware
# classes, one of which, breaks posts to our url. Let's stop that.
@mock.patch.object(settings, 'MIDDLEWARE_CLASSES', [])

View File

@ -73,6 +73,14 @@ First off, pick your client, one of:
Just writes the values to a log file using Python's logging module.
- django_statsd.clients.moz_metlog
Use this to route messages through
_metlog: http://github.com/mozilla-services/metlog-py. Note that
using metlog will require you to bind the metlog instance to bind
the metlog client instance as settings.METLOG.
Usage
-----

1
optional.txt Normal file
View File

@ -0,0 +1 @@
metlog-py