From 8bb73cade24a8a50f2b925b78e4b60ce4776aa84 Mon Sep 17 00:00:00 2001 From: Yann Mahe Date: Thu, 19 Mar 2015 18:01:37 -0400 Subject: [PATCH] 0.5.6 --- CONTRIBUTING.md | 22 ----------------- README.md | 2 ++ setup.py | 5 ++-- statsd.py | 58 ++++++++++++++++++++++++++------------------ tests/test_statsd.py | 22 ++--------------- 5 files changed, 41 insertions(+), 68 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 73d0914..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,22 +0,0 @@ -# Contributing - -We love pull requests. Here's a quick guide. - -Fork, then clone the repo: - - git clone git@github.com:your-username/dogstatsd-python.git - -Make sure the tests pass: - - pip install nose six; python setup.py test - -Make your change. Add tests for your change. Make the tests pass: - - python setup.py test - -Push to your fork and [submit a pull request][pr]. - -[pr]: https://github.com/your-username/dogstatsd-python/compare/DataDog:master...master - -At this point you're waiting on us. We may suggest some changes or -improvements or alternatives. diff --git a/README.md b/README.md index a0acf81..69d692a 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,8 @@ Change Log ---------- - [DEPRECATED] - Date: 2015.03.17 +- 0.5.6 + - Revert to 0.5.3 due to backward incompatibilities. - 0.5.5 - Revert usage of Python property for socket introduced in 0.5.4, to avoid backward incompatibilities, and performance degradation - 0.5.4 diff --git a/setup.py b/setup.py index 7415905..918f79c 100644 --- a/setup.py +++ b/setup.py @@ -3,13 +3,12 @@ setup( name = "dogstatsd-python", - version = "0.5.5", + version = "0.5.6", author = "Datadog, Inc.", author_email = "packages@datadoghq.com", description = "Python bindings to Datadog's API and a user-facing command line tool.", py_modules=['statsd'], license = "BSD", keywords = "datadog data statsd metrics", - url = "http://www.datadoghq.com", - test_suite = "nose.collector" + url = "http://www.datadoghq.com" ) diff --git a/statsd.py b/statsd.py index 2b5ee99..e2c5137 100644 --- a/statsd.py +++ b/statsd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """ DogStatsd is a Python client for DogStatsd, a Statsd fork for Datadog. """ @@ -21,7 +20,7 @@ class DogStatsd(object): OK, WARNING, CRITICAL, UNKNOWN = (0, 1, 2, 3) - def __init__(self, host='localhost', port=8125, max_buffer_size=50): + def __init__(self, host='localhost', port=8125, max_buffer_size = 50): """ Initialize a DogStatsd object. @@ -31,30 +30,29 @@ def __init__(self, host='localhost', port=8125, max_buffer_size=50): :param port: the port of the DogStatsd server. :param max_buffer_size: Maximum number of metric to buffer before sending to the server if sending metrics in batch """ - self._host = host - self._port = int(port) + self._host = None + self._port = None self.socket = None self.max_buffer_size = max_buffer_size self._send = self._send_to_server - + self.connect(host, port) self.encoding = 'utf-8' - def __enter__(self): - self.open_buffer(self.max_buffer_size) - return self - - def __exit__(self, type, value, traceback): - self.close_buffer() - def get_socket(self): ''' Return a connected socket ''' if not self.socket: - self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.socket.connect((self._host, self._port)) + self.connect(self._host, self._port) return self.socket + def __enter__(self): + self.open_buffer(self.max_buffer_size) + return self + + def __exit__(self, type, value, traceback): + self.close_buffer() + def open_buffer(self, max_buffer_size=50): ''' Open a buffer to send a batch of metrics in one packet @@ -67,7 +65,7 @@ def open_buffer(self, max_buffer_size=50): ''' self.max_buffer_size = max_buffer_size - self.buffer = [] + self.buffer= [] self._send = self._send_to_buffer def close_buffer(self): @@ -77,6 +75,15 @@ def close_buffer(self): self._send = self._send_to_server self._flush_buffer() + def connect(self, host, port): + """ + Connect to the statsd server on the given host and port. + """ + self._host = host + self._port = int(port) + self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.socket.connect((self._host, self._port)) + def gauge(self, metric, value, tags=None, sample_rate=1): """ Record the value of a gauge, optionally setting a list of tags and a @@ -176,13 +183,12 @@ def _report(self, metric, metric_type, value, tags, sample_rate): def _send_to_server(self, packet): try: - # If set, use socket directly - (self.socket or self.get_socket()).send(packet.encode(self.encoding)) + self.socket.send(packet.encode(self.encoding)) except socket.error: - log.info("Error submitting packet, will try refreshing the socket") - self.socket = None + log.info("Error submitting metric, will try refreshing the socket") + self.connect(self._host, self._port) try: - self.get_socket().send(packet.encode(self.encoding)) + self.socket.send(packet.encode(self.encoding)) except socket.error: log.exception("Failed to send packet with a newly binded socket") @@ -193,7 +199,7 @@ def _send_to_buffer(self, packet): def _flush_buffer(self): self._send_to_server("\n".join(self.buffer)) - self.buffer = [] + self.buffer=[] def _escape_event_content(self, string): return string.replace('\n', '\\n') @@ -233,7 +239,10 @@ def event(self, title, text, alert_type=None, aggregation_key=None, raise Exception(u'Event "%s" payload is too big (more that 8KB), ' 'event discarded' % title) - self._send(string) + try: + self.socket.send(string.encode(self.encoding)) + except Exception: + log.exception(u'Error submitting event "%s"' % title) def service_check(self, check_name, status, tags=None, timestamp=None, hostname=None, message=None): @@ -255,7 +264,10 @@ def service_check(self, check_name, status, tags=None, timestamp=None, if message: string = u'{0}|m:{1}'.format(string, message) - self._send(string) + try: + self.socket.send(string.encode(self.encoding)) + except Exception: + log.exception(u'Error submitting service check "{0}"'.format(check_name)) statsd = DogStatsd() diff --git a/tests/test_statsd.py b/tests/test_statsd.py index 6c6698f..920c7fd 100644 --- a/tests/test_statsd.py +++ b/tests/test_statsd.py @@ -45,7 +45,7 @@ def setUp(self): self.statsd.socket = FakeSocket() def recv(self): - return self.statsd.get_socket().recv() + return self.statsd.socket.recv() def test_set(self): self.statsd.set('set', 123) @@ -89,7 +89,7 @@ def test_sample_rate(self): assert not self.recv() for i in range(10000): self.statsd.increment('sampled_counter', sample_rate=0.3) - self.assert_almost_equal(3000, len(self.statsd.get_socket().payloads), 150) + self.assert_almost_equal(3000, len(self.statsd.socket.payloads), 150) t.assert_equal('sampled_counter:1|c|@0.3', self.recv()) def test_tags_and_samples(self): @@ -182,24 +182,6 @@ def test_batched_buffer_autoflush(self): def test_module_level_instance(self): t.assert_true(isinstance(statsd.statsd, statsd.DogStatsd)) - def test_instantiating_does_not_connect(self): - dogpound = DogStatsd() - t.assert_equal(None, dogpound.socket) - - def test_accessing_socket_opens_socket(self): - dogpound = DogStatsd() - try: - t.assert_not_equal(None, dogpound.get_socket()) - finally: - dogpound.get_socket().close() - - def test_accessing_socket_multiple_times_returns_same_socket(self): - dogpound = DogStatsd() - fresh_socket = FakeSocket() - dogpound.socket = fresh_socket - t.assert_equal(fresh_socket, dogpound.get_socket()) - t.assert_not_equal(FakeSocket(), dogpound.get_socket()) - if __name__ == '__main__': statsd = statsd