<commit_before># -*- test-case-name: vumi.blinkenlights.tests.test_metrics -*-

from twisted.internet.task import LoopingCall

from vumi.service import Publisher, Consumer
from vumi.blinkenlights.message20110818 import MetricMessage

import time


class MetricManager(Publisher):
    """Utility for creating and monitoring a set of metrics.

    Parameters
    ----------
    prefix : str
        Prefix for the name of all metrics created by this metric set.
    publish_interval : int in seconds
        How often to publish the set of metrics. This should match
        the finest retention level specified in Graphite if you
        are using Graphite to store the metric data points.
    """
    exchange_name = "vumi.metrics"
    exchange_type = "direct"
    routing_key = "vumi.metrics"
    durable = True
    auto_delete = False
    delivery_mode = 2

    def __init__(self, prefix, publish_interval=5):
        self.prefix = prefix
        self._metrics = []  # list of metric objects
        self._publish_interval = publish_interval
        self._task = None  # created in .start()

    def start(self, channel):
        """Start publishing metrics in a loop."""
        super(MetricManager, self).start(channel)
        self._task = LoopingCall(self._publish_metrics)
        self._task.start(self._publish_interval)
        # TODO: capture deferred and add an errback to log errors?

    def stop(self):
        """Stop publishing metrics."""
        self._task.stop()
        self._task = None

    def _publish_metrics(self):
        msg = MetricMessage()
        now = time.time()
        for metric in self._metrics:
            msg.append((metric.name, now, metric.poll()))
        self.publish_message(msg)

    def register(self, metric):
        """Register a new metric object to be managed by this metric set.

        A metric can be registered with only on metric set.

        Parameters
        ----------
        metric : instance of :class:`Metric`
            Metric object to register. Will have prefix added to name.

        Returns
        -------
        metric : instance of :class:`Metric`
            For convenience, returns the metric passed in.
        """
        metric.manage(self.prefix)
        self._metrics.append(metric)
        return metric


class MetricRegistrationError(Exception):
    pass


class Metric(object):
    """Base clase for metrics.

    Parameters
    ----------
    suffix : str
        Partial name for the metric. The metric's full name
        will be constructed when it is registered with a
        :class:`MetricManager`.
    """
    def __init__(self, suffix):
        self.name = None  # set when prefix is set
        self._suffix = suffix

    def manage(self, prefix):
        """Called by a :class:`MetricSet` when this metric is registered."""
        if self.name is not None:
            raise MetricRegistrationError("Metric %s%s already registered"
                                          " with a MetricSet." %
                                          (prefix, self._suffix))
        self.name = prefix + self._suffix

    def poll(self):
        """Called periodically by the managing metric set."""
        raise NotImplementedError("Metric subclasses should implement .pol()")


class SimpleValue(Metric):
    """A metric representing a single value.<commit_msg>Fix strings that reference old MetricSet class.<commit_after># -*- test-case-name: vumi.blinkenlights.tests.test_metrics -*-

from twisted.internet.task import LoopingCall

from vumi.service import Publisher, Consumer
from vumi.blinkenlights.message20110818 import MetricMessage

import time


class MetricManager(Publisher):
    """Utility for creating and monitoring a set of metrics.

    Parameters
    ----------
    prefix : str
        Prefix for the name of all metrics created by this metric set.
    publish_interval : int in seconds
        How often to publish the set of metrics. This should match
        the finest retention level specified in Graphite if you
        are using Graphite to store the metric data points.
    """
    exchange_name = "vumi.metrics"
    exchange_type = "direct"
    routing_key = "vumi.metrics"
    durable = True
    auto_delete = False
    delivery_mode = 2

    def __init__(self, prefix, publish_interval=5):
        self.prefix = prefix
        self._metrics = []  # list of metric objects
        self._publish_interval = publish_interval
        self._task = None  # created in .start()

    def start(self, channel):
        """Start publishing metrics in a loop."""
        super(MetricManager, self).start(channel)
        self._task = LoopingCall(self._publish_metrics)
        self._task.start(self._publish_interval)
        # TODO: capture deferred and add an errback to log errors?

    def stop(self):
        """Stop publishing metrics."""
        self._task.stop()
        self._task = None

    def _publish_metrics(self):
        msg = MetricMessage()
        now = time.time()
        for metric in self._metrics:
            msg.append((metric.name, now, metric.poll()))
        self.publish_message(msg)

    def register(self, metric):
        """Register a new metric object to be managed by this metric set.

        A metric can be registered with only on metric set.

        Parameters
        ----------
        metric : instance of :class:`Metric`
            Metric object to register. Will have prefix added to name.

        Returns
        -------
        metric : instance of :class:`Metric`
            For convenience, returns the metric passed in.
        """
        metric.manage(self.prefix)
        self._metrics.append(metric)
        return metric


class MetricRegistrationError(Exception):
    pass


class Metric(object):
    """Base clase for metrics.

    Parameters
    ----------
    suffix : str
        Partial name for the metric. The metric's full name
        will be constructed when it is registered with a
        :class:`MetricManager`.
    """
    def __init__(self, suffix):
        self.name = None  # set when prefix is set
        self._suffix = suffix

    def manage(self, prefix):
        """Called by :class:`MetricManager` when this metric is registered."""
        if self.name is not None:
            raise MetricRegistrationError("Metric %s%s already registered"
                                          " with a MetricManager." %
                                          (prefix, self._suffix))
        self.name = prefix + self._suffix

    def poll(self):
        """Called periodically by the managing metric set."""
        raise NotImplementedError("Metric subclasses should implement .pol()")


class SimpleValue(Metric):
    """A metric representing a single value.
{'fraction_non_alphanumeric': 0.09022222222222222, 'fraction_numerical': 0.002962962962962963, 'mean_word_length': 2.213231794383627, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '901054', 'n_tokens_mistral': 1723, 'n_tokens_neox': 1662, 'n_words': 614}