Source code for perfmetrics.testing.observation

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function, absolute_import, division
__docformat__ = "restructuredtext en"

#: The statsd metric kind for Gauges
OBSERVATION_KIND_GAUGE = 'g'

#: The statsd metric kind for Counters
OBSERVATION_KIND_COUNTER = 'c'

#: The statsd metric kind for Sets
OBSERVATION_KIND_SET = 's'

#: The statsd metric kind for Timers
OBSERVATION_KIND_TIMER = 'ms'


def _parse_sampling_data(data):
    """
    Parses sampling rate from the provided packet part *data*.

    Raises a `ValueError` if the packet part is invalid sampling data
    """
    if not data.startswith('@'):
        raise ValueError('Expected "@" in sampling data. %s' % data)
    return float(data[1:])


def _as_metric(metric_data):
    """
    Parses a single metric packet, *metric_data*, in to a `Metric`.

    Metrics take the form of <name>:<value>|<type>(|@<sampling_rate>)

    A `ValueError` is raised for invalid data
    """

    sampling = None
    name = None
    value = None
    kind = None
    parts = metric_data.split('|')
    if len(parts) < 2 or len(parts) > 3:
        raise ValueError('Unexpected metric data %s. Wrong number of parts' % metric_data)

    if len(parts) == 3:
        sampling_data = parts.pop(-1)
        sampling = _parse_sampling_data(sampling_data)

    kind = parts[1]
    name, value = parts[0].split(':')

    return Observation(name, value, kind, sampling_rate=sampling)


def _as_metrics(data):
    """
    Parses the statsd *data* packet to a _list_ of metrics.

    .. seealso:: https://github.com/etsy/statsd/blob/master/docs/metric_types.md
    """
    metrics = []

    # Multi metric packets are seperated by newlines
    for metric_data in data.split('\n'):
        metrics.append(_as_metric(metric_data))
    return metrics


[docs]class Observation(object): """ The representation of a single statsd metric. """ #: The metric name name = None #: The value provided for the metric value = None #: The statsd code for the type of metric. e.g. one of the ``METRIC_*_KIND`` constants kind = None #: The rate with which this event has been sampled from (optional) sampling_rate = None def __init__(self, name, value, kind, sampling_rate=None): self.name = name self.value = value self.sampling_rate = sampling_rate self.kind = kind
[docs] @classmethod def make(cls, packet): """ Creates a metric from the provided statsd *packet*. :raises ValueError: if *packet* is a multi metric packet or otherwise invalid. """ metrics = cls.make_all(packet) if len(metrics) != 1: raise ValueError('Must supply a single metric packet. %s supplied' % packet) return metrics[0]
[docs] @classmethod def make_all(cls, packet): """ Makes a list of metrics from the provided statsd *packet*. Like `make` but supports multi metric packets """ return _as_metrics(packet)
def __str__(self): sampling_string = '|@%g' % self.sampling_rate if self.sampling_rate is not None else '' return '%s:%s|%s%s' % (self.name, self.value, self.kind, sampling_string) def __repr__(self): return "%s(name=%r, value=%r, kind=%r, sampling_rate=%r)" % ( self.__class__.__name__, self.name, self.value, self.kind, self.sampling_rate )