From cbde37818da31051fa02131875054ef60d32774d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timothe=CC=81e=20Peignier?= Date: Tue, 23 Oct 2012 03:23:44 +0200 Subject: [PATCH] add derive instrument --- docs/instruments.rst | 7 +++++++ metrology/__init__.py | 4 ++++ metrology/instruments/__init__.py | 1 + metrology/instruments/derive.py | 28 ++++++++++++++++++++++++++++ metrology/registry.py | 5 ++++- tests/instruments/test_derive.py | 28 ++++++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 metrology/instruments/derive.py create mode 100644 tests/instruments/test_derive.py diff --git a/docs/instruments.rst b/docs/instruments.rst index da0e1b1..02ef55b 100644 --- a/docs/instruments.rst +++ b/docs/instruments.rst @@ -17,6 +17,13 @@ Counters .. automodule:: metrology.instruments.counter :members: +Derive +====== + +.. automodule:: metrology.instruments.derive + :members: + + Meters ====== diff --git a/metrology/__init__.py b/metrology/__init__.py index 636dabb..624b85a 100644 --- a/metrology/__init__.py +++ b/metrology/__init__.py @@ -10,6 +10,10 @@ def get(cls, name): def counter(cls, name): return registry.counter(name) + @classmethod + def derive(cls, name): + return registry.derive(name) + @classmethod def meter(cls, name): return registry.meter(name) diff --git a/metrology/instruments/__init__.py b/metrology/instruments/__init__.py index 40d220c..15d5893 100644 --- a/metrology/instruments/__init__.py +++ b/metrology/instruments/__init__.py @@ -1,5 +1,6 @@ # -*- flake8: noqa -*- from metrology.instruments.counter import Counter +from metrology.instruments.derive import Derive from metrology.instruments.gauge import Gauge from metrology.instruments.histogram import Histogram, HistogramUniform, HistogramExponentiallyDecaying from metrology.instruments.meter import Meter diff --git a/metrology/instruments/derive.py b/metrology/instruments/derive.py new file mode 100644 index 0000000..94b56d0 --- /dev/null +++ b/metrology/instruments/derive.py @@ -0,0 +1,28 @@ +from atomic import Atomic + +from metrology.instruments.meter import Meter +from metrology.stats import EWMA + + +class Derive(Meter): + """ + A derive is like a meter but accepts an absolute counter as input. + + derive = Metrology.derive('network.io') + derive.mark() + derive.count + + """ + def __init__(self, average_class=EWMA): + self.last = Atomic(0) + super(Derive, self).__init__(average_class) + + def mark(self, value=1): + """Record an event with the derive. + + :param value: counter value to record + """ + last = self.last.get_and_set(value) + if last <= value: + value = value - last + super(Derive, self).mark(value) diff --git a/metrology/registry.py b/metrology/registry.py index fbc0c8d..14a4684 100644 --- a/metrology/registry.py +++ b/metrology/registry.py @@ -3,7 +3,7 @@ from threading import RLock from metrology.exceptions import RegistryException -from metrology.instruments import Counter, Profiler, Meter, Timer, UtilizationTimer, HistogramUniform +from metrology.instruments import Counter, Derive, Profiler, Meter, Timer, UtilizationTimer, HistogramUniform class Registry(object): @@ -41,6 +41,9 @@ def histogram(self, name, klass=None): klass = HistogramUniform return self.add_or_get(name, klass) + def derive(self, name): + return self.add_or_get(name, Derive) + def profiler(self, name): return self.add_or_get(name, Profiler) diff --git a/tests/instruments/test_derive.py b/tests/instruments/test_derive.py new file mode 100644 index 0000000..d823d70 --- /dev/null +++ b/tests/instruments/test_derive.py @@ -0,0 +1,28 @@ +from unittest import TestCase + +from metrology.instruments.derive import Derive + + +class DeriveTest(TestCase): + def setUp(self): + self.derive = Derive() + + def test_derive(self): + self.derive.mark() + self.assertEqual(1, self.derive.count) + + def test_blank_derive(self): + self.assertEqual(0, self.derive.count) + self.assertEqual(0.0, self.derive.mean_rate) + + def test_derive_value(self): + self.derive.mark(3) + self.assertEqual(3, self.derive.count) + + def test_one_minute_rate(self): + self.derive.mark(1000) + self.derive.tick() + self.assertEqual(200, self.derive.one_minute_rate) + + def tearDown(self): + self.derive.stop()