[Python-modules-commits] [python-statsd] 01/03: Import python-statsd_3.2.orig.tar.gz
Filippo Giunchedi
filippo at moszumanska.debian.org
Fri Oct 23 11:24:39 UTC 2015
This is an automated email from the git hooks/post-receive script.
filippo pushed a commit to tag debian/3.2-1
in repository python-statsd.
commit bdc740b53dc6c471bb7244ae50355322de6de22f
Author: Filippo Giunchedi <filippo at debian.org>
Date: Thu Oct 22 11:35:37 2015 +0100
Import python-statsd_3.2.orig.tar.gz
---
.travis.yml | 7 +-
CHANGES | 14 +
README.rst | 25 +-
docs/conf.py | 6 +-
docs/index.rst | 18 +-
docs/reference.rst | 101 ++++-
docs/tcp.rst | 20 +
docs/types.rst | 6 +-
setup.py | 2 +-
statsd/__init__.py | 5 +-
statsd/client.py | 130 +++++--
statsd/defaults/__init__.py | 1 +
statsd/defaults/django.py | 4 +-
statsd/defaults/env.py | 4 +-
statsd/tests.py | 883 +++++++++++++++++++++++++++++++++-----------
15 files changed, 973 insertions(+), 253 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 9208899..6e420d7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,5 @@
language: python
+sudo: false
python:
- "2.6"
- "2.7"
@@ -6,4 +7,8 @@ python:
- "3.3"
- "3.4"
- "pypy"
-script: nosetests
+install:
+ - pip install -q flake8
+script:
+ - nosetests
+ - flake8 statsd/
diff --git a/CHANGES b/CHANGES
index 771be84..831d06b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,20 @@
Statsd Changelog
================
+Version 3.2
+-----------
+
+- Add an explicit IPv6 flag.
+- Add support for sub-millisecond timings
+
+
+Version 3.1
+-----------
+
+- Add IPv6 support.
+- Add TCPStatsClient/TCPPipeline to support connection-mode clients.
+
+
Version 3.0.1
-------------
diff --git a/README.rst b/README.rst
index 8c48244..ed83a22 100644
--- a/README.rst
+++ b/README.rst
@@ -2,12 +2,33 @@
A Python statsd client
======================
+statsd_ is a friendly front-end to Graphite_. This is a Python client
+for the statsd daemon.
+
.. image:: https://travis-ci.org/jsocol/pystatsd.png?branch=master
:target: https://travis-ci.org/jsocol/pystatsd
:alt: Travis-CI build status
-statsd_ is a friendly front-end to Graphite_. This is a Python client
-for the statsd daemon.
+.. image:: https://pypip.in/v/statsd/badge.png?style=flat
+ :target: https://pypi.python.org/pypi/statsd/
+ :alt: Latest release
+
+.. image:: https://pypip.in/py_versions/statsd/badge.svg?style=flat
+ :target: https://pypi.python.org/pypi/statsd/
+ :alt: Supported Python versions
+
+.. image:: https://pypip.in/wheel/statsd/badge.svg?style=flat
+ :target: https://pypi.python.org/pypi/statsd/
+ :alt: Wheel Status
+
+.. image:: https://pypip.in/d/statsd/badge.png?style=flat
+ :target: https://pypi.python.org/pypi/statsd/
+ :alt: Downloads
+
+:Code: https://github.com/jsocol/pystatsd
+:License: MIT; see LICENSE file
+:Issues: https://github.com/jsocol/pystatsd/issues
+:Documentation: http://statsd.readthedocs.org/
Quickly, to use::
diff --git a/docs/conf.py b/docs/conf.py
index 4e75a4b..419a1da 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -41,16 +41,16 @@ master_doc = 'index'
# General information about the project.
project = u'Python StatsD'
-copyright = u'2014, James Socol'
+copyright = u'2015, James Socol'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = '3.0'
+version = '3.2'
# The full version, including alpha/beta/rc tags.
-release = '3.0'
+release = '3.2.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/index.rst b/docs/index.rst
index ac9f4b1..ed4cb6c 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -6,12 +6,25 @@
Welcome to Python StatsD's documentation!
=========================================
+statsd_ is a friendly front-end to Graphite_. This is a Python client
+for the statsd daemon.
+
.. image:: https://travis-ci.org/jsocol/pystatsd.png?branch=master
:target: https://travis-ci.org/jsocol/pystatsd
:alt: Travis-CI build status
-statsd_ is a friendly front-end to Graphite_. This is a Python client
-for the statsd daemon.
+.. image:: https://pypip.in/v/statsd/badge.png
+ :target: https://pypi.python.org/pypi/statsd/
+ :alt: Latest release
+
+.. image:: https://pypip.in/d/statsd/badge.png
+ :target: https://pypi.python.org/pypi/statsd/
+ :alt: Downloads
+
+:Code: https://github.com/jsocol/pystatsd
+:License: MIT; see LICENSE file
+:Issues: https://github.com/jsocol/pystatsd/issues
+:Documentation: http://statsd.readthedocs.org/
Quickly, to use::
@@ -57,6 +70,7 @@ Contents
types.rst
timing.rst
pipeline.rst
+ tcp.rst
reference.rst
contributing.rst
diff --git a/docs/reference.rst b/docs/reference.rst
index 0c0202e..860b00f 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -9,9 +9,9 @@ statsd_ server supports.
.. note::
- Each public API method supports a ``rate`` parameter, but statsd
- doesn't always use it the same way. See the :ref:`types-chapter` for
- more information.
+ Each public stats API method supports a ``rate`` parameter, but
+ statsd doesn't always use it the same way. See the
+ :ref:`types-chapter` for more information.
.. _StatsClient:
@@ -21,7 +21,7 @@ statsd_ server supports.
::
- StatsClient(host='localhost', port=8125, prefix=None)
+ StatsClient(host='localhost', port=8125, prefix=None, maxudpsize=512)
Create a new ``StatsClient`` instance with the appropriate connection
and prefix information.
@@ -33,6 +33,10 @@ and prefix information.
* ``prefix``: a prefix to distinguish and group stats from an
application or environment.
+* ``maxudpsize``: the largest safe UDP packet to save. 512 is generally
+ considered safe for the public internet, but private networks may
+ support larger packet sizes.
+
.. _incr:
@@ -275,6 +279,95 @@ stats.
This method is not implemented on the base StatsClient class.
+.. _TCPStatsClient:
+
+``TCPStatsClient``
+==================
+
+::
+
+ TCPStatsClient(host='localhost', port=8125, prefix=None, timeout=None)
+
+Create a new ``TCPStatsClient`` instance with the appropriate connection
+and prefix information.
+
+* ``host``: the hostname or IPv4 address of the statsd_ server.
+
+* ``port``: the port of the statsd server.
+
+* ``prefix``: a prefix to distinguish and group stats from an
+ application or environment.
+
+* ``timeout``: socket timeout for any actions on the connection socket.
+
+
+``TCPStatsClient`` implements all methods of ``StatsClient``, including
+``pipeline()``, with the difference that it is not thread safe and it
+can raise exceptions on connection errors. Unlike ``StatsClient`` it
+uses a TCP connection to communicate with StatsD.
+
+In addition to the stats methods, ``TCPStatsClient`` supports the
+following TCP-specific methods.
+
+
+.. _tcp_close:
+
+``close``
+---------
+
+::
+
+ from statsd import TCPStatsClient
+
+ statsd = TCPStatsClient()
+ statsd.incr('some.event')
+ statsd.close()
+
+Closes a connection that's currently open and deletes it's socket. If
+this is called on a ``TCPStatsClient`` which currently has no open
+connection it is a non-action.
+
+
+.. _tcp_connect:
+
+``connect``
+-----------
+
+::
+
+ from statsd import TCPStatsClient
+
+ statsd = TCPStatsClient()
+ statsd.incr('some.event') # calls connect() internally
+ statsd.close()
+ statsd.connect() # creates new connection
+
+Creates a connection to StatsD. If there are errors like connection
+timed out or connection refused, the according exceptions will be
+raised. It is usually not necessary to call this method because sending
+data to StatsD will call ``connect`` implicitely if the current instance
+of ``TCPStatsClient`` does not already hold an open connection.
+
+
+.. _tcp_reconnect:
+
+``reconnect``
+-------------
+
+::
+
+ from statsd import TCPStatsClient
+
+ statsd = TCPStatsClient()
+ statsd.incr('some.event')
+ statsd.reconnect() # closes open connection and creates new one
+
+Closes a currently existing connection and replaces it with a new one.
+If no connection exists already it will simply create a new one.
+Internally this does nothing else than calling ``close()`` and
+``connect()``.
+
+
.. _statsd: https://github.com/etsy/statsd
.. _0ed78be: https://github.com/etsy/statsd/commit/0ed78be7
.. _1c10cfc0ac: https://github.com/etsy/statsd/commit/1c10cfc0ac
diff --git a/docs/tcp.rst b/docs/tcp.rst
new file mode 100644
index 0000000..5437ac5
--- /dev/null
+++ b/docs/tcp.rst
@@ -0,0 +1,20 @@
+.. _tcp-chapter:
+
+==============
+TCPStatsClient
+==============
+
+The ``TCPStatsClient`` class has a very similar interface to
+``StatsClient``, but internally it uses TCP connections instead of UDP.
+These are the main differencies when using ``TCPStatsClient`` compared
+to ``StatsClient``:
+
+* The constructor supports a ``timeout`` parameter to set a timeout on
+ all socket actions.
+
+* ``connect()`` and all methods that send data can potentially raise
+ socket exceptions.
+
+* **It is not thread-safe**, so it is recommended to not share it across
+ threads unless a lot of attention is paid to make sure that no two
+ threads ever use it at once.
diff --git a/docs/types.rst b/docs/types.rst
index bc13d72..9f77280 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -11,7 +11,7 @@ performs different aggregation on each of them. The three main types are
The statsd server collects and aggregates in 30 second intervals before
flushing to Graphite_. Graphite usually stores the most recent data in
1-minute averaged buckets, so when you're looking at a graph, for each
-stat you are typically seing the average value over that minute.
+stat you are typically seeing the average value over that minute.
.. _counter-type:
@@ -79,8 +79,8 @@ Graphite, that's usually per minute).
* The *lower bound* is the lowest value statsd saw for that stat during
that time period.
-* The *mean* is the average of all values statsd saw for that stat
-during that time period.
+* The *mean* is the average of all values statsd saw for that stat
+ during that time period.
* The *90th percentile* is a value *x* such that 90% of all the values
statsd saw for that stat during that time period are below *x*, and
diff --git a/setup.py b/setup.py
index 3e67f09..2a49f38 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ from setuptools import find_packages, setup
setup(
name='statsd',
- version='3.0.1',
+ version='3.2',
description='A simple statsd client.',
long_description=open('README.rst').read(),
author='James Socol',
diff --git a/statsd/__init__.py b/statsd/__init__.py
index a4f0372..ea37107 100644
--- a/statsd/__init__.py
+++ b/statsd/__init__.py
@@ -1,8 +1,9 @@
from __future__ import absolute_import
from .client import StatsClient
+from .client import TCPStatsClient
-VERSION = (3, 0, 1)
+VERSION = (3, 2, 0)
__version__ = '.'.join(map(str, VERSION))
-__all__ = ['StatsClient']
+__all__ = ['StatsClient', 'TCPStatsClient']
diff --git a/statsd/client.py b/statsd/client.py
index 4ea0b57..09ebd2d 100644
--- a/statsd/client.py
+++ b/statsd/client.py
@@ -1,11 +1,13 @@
from __future__ import with_statement
+from collections import deque
from functools import wraps
import random
import socket
import time
+import abc
-__all__ = ['StatsClient']
+__all__ = ['StatsClient', 'TCPStatsClient']
class Timer(object):
@@ -27,7 +29,7 @@ class Timer(object):
try:
return_value = f(*args, **kwargs)
finally:
- elapsed_time_ms = int(round(1000 * (time.time() - start_time)))
+ elapsed_time_ms = 1000.0 * (time.time() - start_time)
self.client.timing(self.stat, elapsed_time_ms, self.rate)
return return_value
return _wrapped
@@ -48,7 +50,7 @@ class Timer(object):
if self._start_time is None:
raise RuntimeError('Timer has not started.')
dt = time.time() - self._start_time
- self.ms = int(round(1000 * dt)) # Convert to milliseconds.
+ self.ms = 1000.0 * dt # Convert to milliseconds.
if send:
self.send()
return self
@@ -62,26 +64,25 @@ class Timer(object):
self.client.timing(self.stat, self.ms, self.rate)
-class StatsClient(object):
- """A client for statsd."""
+class StatsClientBase(object):
+ """A Base class for various statsd clients."""
- def __init__(self, host='localhost', port=8125, prefix=None,
- maxudpsize=512):
- """Create a new client."""
- self._addr = (socket.gethostbyname(host), port)
- self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- self._prefix = prefix
- self._maxudpsize = maxudpsize
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def _send(self):
+ pass
+ @abc.abstractmethod
def pipeline(self):
- return Pipeline(self)
+ pass
def timer(self, stat, rate=1):
return Timer(self, stat, rate)
def timing(self, stat, delta, rate=1):
"""Send new timing information. `delta` is in milliseconds."""
- self._send_stat(stat, '%d|ms' % delta, rate)
+ self._send_stat(stat, '%0.6f|ms' % delta, rate)
def incr(self, stat, count=1, rate=1):
"""Increment a stat by `count`."""
@@ -126,21 +127,88 @@ class StatsClient(object):
if data:
self._send(data)
+
+class StatsClient(StatsClientBase):
+ """A client for statsd."""
+
+ def __init__(self, host='localhost', port=8125, ipv6=False, prefix=None,
+ maxudpsize=512):
+ """Create a new client."""
+ fam = socket.AF_INET6 if ipv6 else socket.AF_INET
+ family, _, _, _, addr = socket.getaddrinfo(
+ host, port, fam, socket.SOCK_DGRAM)[0]
+ self._addr = addr
+ self._sock = socket.socket(family, socket.SOCK_DGRAM)
+ self._prefix = prefix
+ self._maxudpsize = maxudpsize
+
def _send(self, data):
"""Send data to statsd."""
try:
self._sock.sendto(data.encode('ascii'), self._addr)
- except socket.error:
+ except (socket.error, RuntimeError):
# No time for love, Dr. Jones!
pass
+ def pipeline(self):
+ return Pipeline(self)
+
+
+class TCPStatsClient(StatsClientBase):
+ """TCP version of StatsClient."""
+
+ def __init__(self, host='localhost', port=8125, ipv6=False, prefix=None,
+ timeout=None):
+ """Create a new client."""
+ self._host = host
+ self._port = port
+ self._ipv6 = ipv6
+ self._timeout = timeout
+ self._prefix = prefix
+ self._sock = None
+
+ def _send(self, data):
+ """Send data to statsd."""
+ if not self._sock:
+ self.connect()
+ self._do_send(data)
+
+ def _do_send(self, data):
+ self._sock.sendall(data.encode('ascii') + b'\n')
+
+ def close(self):
+ if self._sock and hasattr(self._sock, 'close'):
+ self._sock.close()
+ self._sock = None
+
+ def connect(self):
+ fam = socket.AF_INET6 if self._ipv6 else socket.AF_INET
+ family, _, _, _, addr = socket.getaddrinfo(
+ self._host, self._port, fam, socket.SOCK_STREAM)[0]
+ self._sock = socket.socket(family, socket.SOCK_STREAM)
+ self._sock.settimeout(self._timeout)
+ self._sock.connect(addr)
+
+ def pipeline(self):
+ return TCPPipeline(self)
+
+ def reconnect(self, data):
+ self.close()
+ self.connect()
+
+
+class PipelineBase(StatsClientBase):
+
+ __metaclass__ = abc.ABCMeta
-class Pipeline(StatsClient):
def __init__(self, client):
self._client = client
self._prefix = client._prefix
- self._maxudpsize = client._maxudpsize
- self._stats = []
+ self._stats = deque()
+
+ @abc.abstractmethod
+ def _send(self):
+ pass
def _after(self, data):
if data is not None:
@@ -153,15 +221,35 @@ class Pipeline(StatsClient):
self.send()
def send(self):
- # Use pop(0) to preserve the order of the stats.
if not self._stats:
return
- data = self._stats.pop(0)
+ self._send()
+
+ def pipeline(self):
+ return self.__class__(self)
+
+
+class Pipeline(PipelineBase):
+
+ def __init__(self, client):
+ super(Pipeline, self).__init__(client)
+ self._maxudpsize = client._maxudpsize
+
+ def _send(self):
+ data = self._stats.popleft()
while self._stats:
- stat = self._stats.pop(0)
+ # Use popleft to preserve the order of the stats.
+ stat = self._stats.popleft()
if len(stat) + len(data) + 1 >= self._maxudpsize:
self._client._after(data)
data = stat
else:
data += '\n' + stat
self._client._after(data)
+
+
+class TCPPipeline(PipelineBase):
+
+ def _send(self):
+ self._client._after('\n'.join(self._stats))
+ self._stats.clear()
diff --git a/statsd/defaults/__init__.py b/statsd/defaults/__init__.py
index 2f2de3b..21851e3 100644
--- a/statsd/defaults/__init__.py
+++ b/statsd/defaults/__init__.py
@@ -1,4 +1,5 @@
HOST = 'localhost'
PORT = 8125
+IPV6 = False
PREFIX = None
MAXUDPSIZE = 512
diff --git a/statsd/defaults/django.py b/statsd/defaults/django.py
index c4c2951..74da212 100644
--- a/statsd/defaults/django.py
+++ b/statsd/defaults/django.py
@@ -12,4 +12,6 @@ if statsd is None:
port = getattr(settings, 'STATSD_PORT', defaults.PORT)
prefix = getattr(settings, 'STATSD_PREFIX', defaults.PREFIX)
maxudpsize = getattr(settings, 'STATSD_MAXUDPSIZE', defaults.MAXUDPSIZE)
- statsd = StatsClient(host, port, prefix, maxudpsize)
+ ipv6 = getattr(settings, 'STATSD_IPV6', defaults.IPV6)
+ statsd = StatsClient(host=host, port=port, prefix=prefix,
+ maxudpsize=maxudpsize, ipv6=ipv6)
diff --git a/statsd/defaults/env.py b/statsd/defaults/env.py
index eb857f9..1ee863f 100644
--- a/statsd/defaults/env.py
+++ b/statsd/defaults/env.py
@@ -12,4 +12,6 @@ if statsd is None:
port = int(os.getenv('STATSD_PORT', defaults.PORT))
prefix = os.getenv('STATSD_PREFIX', defaults.PREFIX)
maxudpsize = int(os.getenv('STATSD_MAXUDPSIZE', defaults.MAXUDPSIZE))
- statsd = StatsClient(host, port, prefix, maxudpsize)
+ ipv6 = bool(int(os.getenv('STATSD_IPV6', defaults.IPV6)))
+ statsd = StatsClient(host=host, port=port, prefix=prefix,
+ maxudpsize=maxudpsize, ipv6=ipv6)
diff --git a/statsd/tests.py b/statsd/tests.py
index 751815c..4971d52 100644
--- a/statsd/tests.py
+++ b/statsd/tests.py
@@ -7,22 +7,65 @@ import mock
from nose.tools import eq_
from statsd import StatsClient
+from statsd import TCPStatsClient
ADDR = (socket.gethostbyname('localhost'), 8125)
-def _client(prefix=None):
- sc = StatsClient(host=ADDR[0], port=ADDR[1], prefix=prefix)
+# proto specific methods to get the socket method to send data
+send_method = {
+ 'udp': lambda x: x.sendto,
+ 'tcp': lambda x: x.sendall,
+}
+
+
+# proto specific methods to create the expected value
+make_val = {
+ 'udp': lambda x, addr: mock.call(str.encode(x), addr),
+ 'tcp': lambda x, addr: mock.call(str.encode(x + '\n')),
+}
+
+
+def _udp_client(prefix=None, addr=None, port=None, ipv6=False):
+ if not addr:
+ addr = ADDR[0]
+ if not port:
+ port = ADDR[1]
+ sc = StatsClient(host=addr, port=port, prefix=prefix, ipv6=ipv6)
sc._sock = mock.Mock()
return sc
-def _sock_check(cl, count, val=None):
- eq_(cl._sock.sendto.call_count, count)
+def _tcp_client(prefix=None, addr=None, port=None, timeout=None, ipv6=False):
+ if not addr:
+ addr = ADDR[0]
+ if not port:
+ port = ADDR[1]
+ sc = TCPStatsClient(host=addr, port=port, prefix=prefix, timeout=timeout,
+ ipv6=ipv6)
+ sc._sock = mock.Mock()
+ return sc
+
+
+def _timer_check(sock, count, proto, start, end):
+ send = send_method[proto](sock)
+ eq_(send.call_count, count)
+ value = send.call_args[0][0].decode('ascii')
+ exp = re.compile('^%s:\d+|%s$' % (start, end))
+ assert exp.match(value)
+
+
+def _sock_check(sock, count, proto, val=None, addr=None):
+ send = send_method[proto](sock)
+ eq_(send.call_count, count)
+ if not addr:
+ addr = ADDR
if val is not None:
- val = val.encode('ascii')
- eq_(cl._sock.sendto.call_args, ((val, ADDR), {}))
+ eq_(
+ send.call_args,
+ make_val[proto](val, addr),
+ )
class assert_raises(object):
@@ -82,54 +125,132 @@ class assert_raises(object):
return True
+def _test_incr(cl, proto):
+ cl.incr('foo')
+ _sock_check(cl._sock, 1, proto, val='foo:1|c')
+
+ cl.incr('foo', 10)
+ _sock_check(cl._sock, 2, proto, val='foo:10|c')
+
+ cl.incr('foo', 1.2)
+ _sock_check(cl._sock, 3, proto, val='foo:1.2|c')
+
+ cl.incr('foo', 10, rate=0.5)
+ _sock_check(cl._sock, 4, proto, val='foo:10|c|@0.5')
+
+
+ at mock.patch.object(random, 'random', lambda: -1)
+def test_incr_udp():
+ """StatsClient.incr works."""
+ cl = _udp_client()
+ _test_incr(cl, 'udp')
+
+
@mock.patch.object(random, 'random', lambda: -1)
-def test_incr():
- sc = _client()
+def test_incr_tcp():
+ """TCPStatsClient.incr works."""
+ cl = _tcp_client()
+ _test_incr(cl, 'tcp')
+
+
+def _test_decr(cl, proto):
+ cl.decr('foo')
+ _sock_check(cl._sock, 1, proto, 'foo:-1|c')
- sc.incr('foo')
- _sock_check(sc, 1, 'foo:1|c')
+ cl.decr('foo', 10)
+ _sock_check(cl._sock, 2, proto, 'foo:-10|c')
- sc.incr('foo', 10)
- _sock_check(sc, 2, 'foo:10|c')
+ cl.decr('foo', 1.2)
+ _sock_check(cl._sock, 3, proto, 'foo:-1.2|c')
- sc.incr('foo', 1.2)
- _sock_check(sc, 3, 'foo:1.2|c')
+ cl.decr('foo', 1, rate=0.5)
+ _sock_check(cl._sock, 4, proto, 'foo:-1|c|@0.5')
- sc.incr('foo', 10, rate=0.5)
- _sock_check(sc, 4, 'foo:10|c|@0.5')
+
+ at mock.patch.object(random, 'random', lambda: -1)
+def test_decr_udp():
+ """StatsClient.decr works."""
+ cl = _udp_client()
+ _test_decr(cl, 'udp')
@mock.patch.object(random, 'random', lambda: -1)
-def test_decr():
- sc = _client()
+def test_decr_tcp():
+ """TCPStatsClient.decr works."""
+ cl = _tcp_client()
+ _test_decr(cl, 'tcp')
- sc.decr('foo')
- _sock_check(sc, 1, 'foo:-1|c')
- sc.decr('foo', 10)
- _sock_check(sc, 2, 'foo:-10|c')
+def _test_gauge(cl, proto):
+ cl.gauge('foo', 30)
+ _sock_check(cl._sock, 1, proto, 'foo:30|g')
- sc.decr('foo', 1.2)
- _sock_check(sc, 3, 'foo:-1.2|c')
+ cl.gauge('foo', 1.2)
+ _sock_check(cl._sock, 2, proto, 'foo:1.2|g')
- sc.decr('foo', 1, rate=0.5)
- _sock_check(sc, 4, 'foo:-1|c|@0.5')
+ cl.gauge('foo', 70, rate=0.5)
+ _sock_check(cl._sock, 3, proto, 'foo:70|g|@0.5')
@mock.patch.object(random, 'random', lambda: -1)
-def test_gauge():
- sc = _client()
- sc.gauge('foo', 30)
- _sock_check(sc, 1, 'foo:30|g')
+def test_gauge_udp():
+ """StatsClient.gauge works."""
+ cl = _udp_client()
+ _test_gauge(cl, 'udp')
- sc.gauge('foo', 1.2)
- _sock_check(sc, 2, 'foo:1.2|g')
- sc.gauge('foo', 70, rate=0.5)
- _sock_check(sc, 3, 'foo:70|g|@0.5')
+ at mock.patch.object(random, 'random', lambda: -1)
+def test_gauge_tcp():
+ """TCPStatsClient.gauge works."""
+ cl = _tcp_client()
+ _test_gauge(cl, 'tcp')
-def test_gauge_delta():
+def _test_ipv6(cl, proto, addr):
+ cl.gauge('foo', 30)
+ _sock_check(cl._sock, 1, proto, 'foo:30|g', addr=addr)
+
+
+def test_ipv6_udp():
+ """StatsClient can use to IPv6 address."""
+ addr = ('::1', 8125, 0, 0)
+ cl = _udp_client(addr=addr[0], ipv6=True)
+ _test_ipv6(cl, 'udp', addr)
+
+
+def test_ipv6_tcp():
+ """TCPStatsClient can use to IPv6 address."""
+ addr = ('::1', 8125, 0, 0)
+ cl = _tcp_client(addr=addr[0], ipv6=True)
+ _test_ipv6(cl, 'tcp', addr)
+
+
+def _test_resolution(cl, proto, addr):
+ cl.incr('foo')
+ _sock_check(cl._sock, 1, proto, 'foo:1|c', addr=addr)
+
+
+def test_ipv6_resolution_udp():
+ cl = _udp_client(addr='localhost', ipv6=True)
+ _test_resolution(cl, 'udp', ('::1', 8125, 0, 0))
+
+
+def test_ipv6_resolution_tcp():
+ cl = _tcp_client(addr='localhost', ipv6=True)
+ _test_resolution(cl, 'tcp', ('::1', 8125, 0, 0))
+
+
+def test_ipv4_resolution_udp():
+ cl = _udp_client(addr='localhost')
+ _test_resolution(cl, 'udp', ('127.0.0.1', 8125))
+
+
+def test_ipv4_resolution_tcp():
+ cl = _tcp_client(addr='localhost')
+ _test_resolution(cl, 'tcp', ('127.0.0.1', 8125))
+
+
+def _test_gauge_delta(cl, proto):
tests = (
(12, '+12'),
(-13, '-13'),
@@ -138,65 +259,126 @@ def test_gauge_delta():
)
def _check(num, result):
- sc = _client()
- sc.gauge('foo', num, delta=True)
- _sock_check(sc, 1, 'foo:%s|g' % result)
+ cl._sock.reset_mock()
+ cl.gauge('foo', num, delta=True)
+ _sock_check(cl._sock, 1, proto, 'foo:%s|g' % result)
for num, result in tests:
- yield _check, num, result
+ _check(num, result)
-def test_gauge_absolute_negative():
- sc = _client()
- sc.gauge('foo', -5, delta=False)
- _sock_check(sc, 1, 'foo:0|g\nfoo:-5|g')
+ at mock.patch.object(random, 'random', lambda: -1)
+def test_gauge_delta_udp():
+ """StatsClient.gauge works with delta values."""
+ cl = _udp_client()
+ _test_gauge_delta(cl, 'udp')
- at mock.patch.object(random, 'random')
-def test_gauge_absolute_negative_rate(mock_random):
- sc = _client()
+ at mock.patch.object(random, 'random', lambda: -1)
+def test_gauge_delta_tcp():
+ """TCPStatsClient.gauge works with delta values."""
+ cl = _tcp_client()
+ _test_gauge_delta(cl, 'tcp')
+
+
+def _test_gauge_absolute_negative(cl, proto):
+ cl.gauge('foo', -5, delta=False)
+ _sock_check(cl._sock, 1, 'foo:0|g\nfoo:-5|g')
+
+
+ at mock.patch.object(random, 'random', lambda: -1)
+def test_gauge_absolute_negative_udp():
+ """StatsClient.gauge works with absolute negative value."""
+ cl = _udp_client()
+ _test_gauge_delta(cl, 'udp')
+
+
+ at mock.patch.object(random, 'random', lambda: -1)
+def test_gauge_absolute_negative_tcp():
+ """TCPStatsClient.gauge works with absolute negative value."""
+ cl = _tcp_client()
+ _test_gauge_delta(cl, 'tcp')
+
+
+def _test_gauge_absolute_negative_rate(cl, proto, mock_random):
mock_random.return_value = -1
- sc.gauge('foo', -1, rate=0.5, delta=False)
- _sock_check(sc, 1, 'foo:0|g\nfoo:-1|g')
+ cl.gauge('foo', -1, rate=0.5, delta=False)
+ _sock_check(cl._sock, 1, proto, 'foo:0|g\nfoo:-1|g')
mock_random.return_value = 2
- sc.gauge('foo', -2, rate=0.5, delta=False)
- _sock_check(sc, 1, 'foo:0|g\nfoo:-1|g') # Should not have changed.
+ cl.gauge('foo', -2, rate=0.5, delta=False)
+ # Should not have changed.
+ _sock_check(cl._sock, 1, proto, 'foo:0|g\nfoo:-1|g')
- at mock.patch.object(random, 'random', lambda: -1)
-def test_set():
- sc = _client()
- sc.set('foo', 10)
- _sock_check(sc, 1, 'foo:10|s')
+ at mock.patch.object(random, 'random')
+def test_gauge_absolute_negative_rate_udp(mock_random):
+ """StatsClient.gauge works with absolute negative value and rate."""
+ cl = _udp_client()
+ _test_gauge_absolute_negative_rate(cl, 'udp', mock_random)
+
+
+ at mock.patch.object(random, 'random')
+def test_gauge_absolute_negative_rate_tcp(mock_random):
+ """TCPStatsClient.gauge works with absolute negative value and rate."""
+ cl = _tcp_client()
+ _test_gauge_absolute_negative_rate(cl, 'tcp', mock_random)
+
+
+def _test_set(cl, proto):
+ cl.set('foo', 10)
+ _sock_check(cl._sock, 1, proto, 'foo:10|s')
- sc.set('foo', 2.3)
- _sock_check(sc, 2, 'foo:2.3|s')
+ cl.set('foo', 2.3)
+ _sock_check(cl._sock, 2, proto, 'foo:2.3|s')
- sc.set('foo', 'bar')
- _sock_check(sc, 3, 'foo:bar|s')
+ cl.set('foo', 'bar')
+ _sock_check(cl._sock, 3, proto, 'foo:bar|s')
- sc.set('foo', 2.3, 0.5)
- _sock_check(sc, 4, 'foo:2.3|s|@0.5')
+ cl.set('foo', 2.3, 0.5)
+ _sock_check(cl._sock, 4, proto, 'foo:2.3|s|@0.5')
@mock.patch.object(random, 'random', lambda: -1)
-def test_timing():
- sc = _client()
+def test_set_udp():
+ """StatsClient.set works."""
+ cl = _udp_client()
+ _test_set(cl, 'udp')
- sc.timing('foo', 100)
- _sock_check(sc, 1, 'foo:100|ms')
- sc.timing('foo', 350)
- _sock_check(sc, 2, 'foo:350|ms')
+ at mock.patch.object(random, 'random', lambda: -1)
+def test_set_tcp():
+ """TCPStatsClient.set works."""
+ cl = _tcp_client()
+ _test_set(cl, 'tcp')
+
+
+def _test_timing(cl, proto):
+ cl.timing('foo', 100)
+ _sock_check(cl._sock, 1, proto, 'foo:100.000000|ms')
+
+ cl.timing('foo', 350)
+ _sock_check(cl._sock, 2, proto, 'foo:350.000000|ms')
+
+ cl.timing('foo', 100, rate=0.5)
... 739 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-statsd.git
More information about the Python-modules-commits
mailing list