Merge pull request #3 from sprockets/final-touches

Final touches
This commit is contained in:
Gavin M. Roy 2016-01-29 10:05:02 -05:00
commit 1d6c2b7597
13 changed files with 83 additions and 12 deletions

View file

@ -13,3 +13,13 @@ script: nosetests --with-coverage
after_success:
- codecov
sudo: false
deploy:
provider: pypi
user: sprockets
password:
secure: EMA/RMTwgN452CnnJxf34KIkUEY4ehiPe7kgF35i11iGti3AR/i4yxi78lD/9010rfynoRZL6eKMg+RiG1uxEQckkbu/HKcjz1VlY+Sz4KYPzY9xAcyf6kLZ4CxglfhXr+Fz0nGjsfNoM5vKVShXOVH1lJBTSjnNqHV0pt1U6R0dPhyDObfsJg/0Pax+Cyld8XaFXRGs5VcYvhkzn+L3bpTUD7EfVIsdEPO9hmz1tH9xgsVtw6Qacgpub6Zns3ODX4hj/rYS7jmQSlWBQHH2UyhQOSZ1hF9JoECMjBOAHLQknnTIGeVdT/ma20Snk3IaaCK0qEmfMUC/WMOCn3J9MlPLTbHN1sr2/6OL3zSnJKO5Cd1K7zzZfro6dkv2MaqrGuo/ZxgZPPftj+fX8pXdd7gXCtjLTUmSzIBABuWuYv9toDd8drII+qgAWv2f5GEZSkUL0OnjKlse+vWtdtAIVl4Jz9RZnwS4V9f+dHaNLiuvFCiyRzY4BgBfLOoYDi/1FOu42y+QNaQq4uTfeioUx6bl+MQOiJ43c1v0Ib8hxpm34nU9L7IFLcrrmjA6PK585Fcemk6lUrRSozrIzptBLmIAr5GsHjuBgGuWV19bR7RUA/hvWQhmpS6rqFqJAEQ1cWK+LKdHIKY/XFU3lI6beh8P+L0UEt55xHyxDFfsWKE=
on:
tags: true
distributions: sdist bdist_wheel
all_branches: true
python: 3.4

View file

@ -21,6 +21,7 @@ implements the same interface:
self.record_timing(self.request.request_time(), 'request', 'lookup')
.. method:: increase_counter(*path, amount=1)
:noindex:
:param path: counter path to increment
:keyword int amount: value to increase the counter by
@ -30,6 +31,7 @@ implements the same interface:
self.increase_counter('db', 'query', 'foo')
.. method:: execution_timer(*path)
:noindex:
:param path: timing path to record
@ -41,6 +43,16 @@ implements the same interface:
with self.execution_timer('db', 'query', 'foo'):
rows = yield self.session.query('SELECT * FROM foo')
.. method:: set_metric_tag(tag, value)
:noindex:
:param str tag: the tag to set
:param str value: the value to assign to the tag
This method stores a tag and value pair to be reported with
metrics. It is only implemented on back-ends that support
tagging metrics (e.g., :class:`sprockets.mixins.metrics.InfluxDBMixin`)
Statsd Implementation
---------------------

View file

@ -21,7 +21,7 @@ master_doc = 'index'
exclude_patterns = []
pygments_style = 'sphinx'
html_style = 'custom.css'
html_static_path = ['.']
html_static_path = ['_static']
html_theme = 'alabaster'
html_theme_path = [alabaster.get_path()]
html_sidebars = {
@ -33,6 +33,7 @@ html_theme_options = {
'description': 'Application metrics tracker',
'github_banner': True,
'travis_button': True,
'codecov_button': True,
}
intersphinx_mapping = {

View file

@ -3,12 +3,13 @@
Release History
===============
`Next Release`_
---------------
`0.9.0`_ (27-Jan-2016)
----------------------
- Add :class:`sprockets.mixins.metrics.StatsdMixin`
- Add :class:`sprockets.mixins.metrics.testing.FakeStatsdServer`
- Add :class:`sprockets.mixins.metrics.testing.FakeInfluxHandler`
- Add :class:`sprockets.mixins.metrics.InfluxDBMixin`
- Add :class:`sprockets.mixins.metrics.influxdb.InfluxDBConnection`
.. _Next Release: https://github.com/sprockets/sprockets.mixins.metrics/compare/0.0.0...master
.. _Next Release: https://github.com/sprockets/sprockets.mixins.metrics/compare/0.9.0...master
.. _0.9.0: https://github.com/sprockets/sprockets.mixins.metrics/compare/0.0.0...0.9.0

View file

@ -2,7 +2,7 @@ import os
import signal
from sprockets.mixins import metrics
from tornado import gen, ioloop, web
from tornado import concurrent, gen, ioloop, web
class SimpleHandler(metrics.InfluxDBMixin, web.RequestHandler):
@ -32,6 +32,16 @@ class SimpleHandler(metrics.InfluxDBMixin, web.RequestHandler):
"""
@gen.coroutine
def prepare(self):
maybe_future = super(SimpleHandler, self).prepare()
if concurrent.is_future(maybe_future):
yield maybe_future
if 'Correlation-ID' in self.request.headers:
self.set_metric_tag('correlation_id',
self.request.headers['Correlation-ID'])
@gen.coroutine
def get(self):
with self.execution_timer('sleepytime'):

View file

@ -1,7 +1,7 @@
import signal
from sprockets.mixins import metrics
from tornado import gen, ioloop, web
from tornado import concurrent, gen, ioloop, web
class SimpleHandler(metrics.StatsdMixin, web.RequestHandler):
@ -14,6 +14,16 @@ class SimpleHandler(metrics.StatsdMixin, web.RequestHandler):
"""
@gen.coroutine
def prepare(self):
maybe_future = super(SimpleHandler, self).prepare()
if concurrent.is_future(maybe_future):
yield maybe_future
if 'Correlation-ID' in self.request.headers:
self.set_metric_tag('correlation_id',
self.request.headers['Correlation-ID'])
@gen.coroutine
def get(self):
yield gen.sleep(0.25)

View file

@ -1,3 +1,5 @@
[bdist_wheel]
universal = 1
[nosetests]
cover-package = sprockets.mixins.metrics
cover-branches = 1

View file

@ -39,7 +39,7 @@ setuptools.setup(
packages=setuptools.find_packages(exclude=['examples.']),
namespace_packages=['sprockets', 'sprockets.mixins'],
classifiers=[
'Development Status :: 1 - Planning',
'Development Status :: 3 - Alpha',
'Environment :: No Input/Output (Daemon)',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',

View file

@ -1,6 +1,6 @@
from .influxdb import InfluxDBMixin
from .statsd import StatsdMixin
version_info = (0, 0, 0)
version_info = (0, 9, 0)
__version__ = '.'.join(str(v) for v in version_info)
__all__ = ['InfluxDBMixin', 'StatsdMixin']

View file

@ -137,6 +137,6 @@ class InfluxDBMixin(object):
self.record_timing(self.request.request_time(), 'duration')
self.settings[self.SETTINGS_KEY]['db_connection'].submit(
self.settings[self.SETTINGS_KEY]['measurement'],
('{}={}'.format(k, v) for k, v in self.__tags.items()),
('{}="{}"'.format(k, v) for k, v in self.__tags.items()),
self.__metrics,
)

View file

@ -39,6 +39,9 @@ class StatsdMixin(object):
settings.setdefault('port', '8125')
self.__status_code = None
def set_metric_tag(self, tag, value):
"""Ignored for statsd since it does not support tagging."""
def set_status(self, status_code, reason=None):
# Extended to track status code to avoid referencing the
# _status internal variable

View file

@ -1,6 +1,7 @@
import logging
import socket
import time
import uuid
from tornado import gen, testing, web
import mock
@ -106,6 +107,11 @@ class StatsdMethodTimingTests(testing.AsyncHTTPTestCase):
for path, value, stat_type in self.statsd.find_metrics(prefix, 'ms'):
assert_between(250.0, float(value), 300.0)
def test_that_add_metric_tag_is_ignored(self):
response = self.fetch('/',
headers={'Correlation-ID': 'does not matter'})
self.assertEqual(response.code, 204)
class InfluxDbTests(testing.AsyncHTTPTestCase):
@ -140,9 +146,10 @@ class InfluxDbTests(testing.AsyncHTTPTestCase):
if key.startswith('my-service,'):
tag_dict = dict(a.split('=') for a in key.split(',')[1:])
self.assertEqual(tag_dict['handler'],
'examples.influxdb.SimpleHandler')
self.assertEqual(tag_dict['method'], 'GET')
self.assertEqual(tag_dict['host'], socket.gethostname())
'"examples.influxdb.SimpleHandler"')
self.assertEqual(tag_dict['method'], '"GET"')
self.assertEqual(tag_dict['host'],
'"{}"'.format(socket.gethostname()))
value_dict = dict(a.split('=') for a in fields.split(','))
assert_between(0.25, float(value_dict['duration']), 0.3)
@ -189,3 +196,18 @@ class InfluxDbTests(testing.AsyncHTTPTestCase):
response = self.fetch('/')
self.assertEqual(response.code, 204)
self.assertIs(cfg['db_connection'], conn)
def test_that_metric_tag_is_tracked(self):
cid = str(uuid.uuid4())
response = self.fetch('/', headers={'Correlation-ID': cid})
self.assertEqual(response.code, 204)
for key, fields, timestamp in self.influx_messages:
if key.startswith('my-service,'):
tag_dict = dict(a.split('=') for a in key.split(',')[1:])
self.assertEqual(tag_dict['correlation_id'],
'"{}"'.format(cid))
break
else:
self.fail('Expected to find "request" metric in {!r}'.format(
list(self.application.influx_db['requests'])))