Merge lp:~theiw/txstatsd/txstatsd-metermetric into lp:txstatsd

Proposed by Ian Wilkinson
Status: Merged
Approved by: Sidnei da Silva
Approved revision: 25
Merged at revision: 25
Proposed branch: lp:~theiw/txstatsd/txstatsd-metermetric
Merge into: lp:txstatsd
Diff against target: 756 lines (+627/-1)
10 files modified
README (+3/-0)
txstatsd/metrics/metermetric.py (+104/-0)
txstatsd/metrics/metrics.py (+11/-0)
txstatsd/server/processor.py (+39/-0)
txstatsd/service.py (+6/-0)
txstatsd/stats/ewma.py (+70/-0)
txstatsd/tests/stats/test_ewma.py (+315/-0)
txstatsd/tests/test_metrics.py (+6/-0)
txstatsd/tests/test_processor.py (+72/-0)
txstatsd/version.py (+1/-1)
To merge this branch: bzr merge lp:~theiw/txstatsd/txstatsd-metermetric
Reviewer Review Type Date Requested Status
Sidnei da Silva Approve
Lucio Torre (community) Approve
Review via email: mp+73032@code.launchpad.net

Description of the change

Introduce support for Coda Hale's meter metric.

To post a comment you must log in.
Revision history for this message
Lucio Torre (lucio.torre) :
review: Approve
Revision history for this message
Sidnei da Silva (sidnei) wrote :

im under the impression that those would be better implemented as functions on the graphite side, but other than that looks good to me. +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'README'
--- README 2011-06-20 19:11:22 +0000
+++ README 2011-08-26 12:28:49 +0000
@@ -11,6 +11,9 @@
11* The txstatsd python package, containing a server and a client implementation11* The txstatsd python package, containing a server and a client implementation
12 for the statsd protocol.12 for the statsd protocol.
1313
14* The metrics support borrows from Coda Hale's Metrics project
15 https://github.com/codahale/metrics.
16
14License17License
15-------18-------
1619
1720
=== added file 'txstatsd/metrics/metermetric.py'
--- txstatsd/metrics/metermetric.py 1970-01-01 00:00:00 +0000
+++ txstatsd/metrics/metermetric.py 2011-08-26 12:28:49 +0000
@@ -0,0 +1,104 @@
1
2import time
3
4from txstatsd.metrics.metric import Metric
5from txstatsd.stats.ewma import Ewma
6
7
8class MeterMetric(Metric):
9 """
10 A meter metric which measures mean throughput and one-, five-, and
11 fifteen-minute exponentially-weighted moving average throughputs.
12
13 See:
14 - U{EMA
15 <http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average>}
16 """
17
18 def __init__(self, connection, name, sample_rate=1):
19 """Construct a metric that reports samples to the supplied
20 C{connection}.
21
22 @param connection: The connection endpoint representing
23 the StatsD server.
24 @param name: Indicates what is being instrumented.
25 @param sample_rate: Restrict the number of samples sent
26 to the StatsD server based on the supplied C{sample_rate}.
27 """
28 Metric.__init__(self, connection, name, sample_rate=sample_rate)
29
30 def mark(self, value=1):
31 """Mark the occurrence of a given number (C{value}) of events."""
32 self.send("%s|m" % value)
33
34
35class MeterMetricReporter(object):
36 """
37 A meter metric which measures mean throughput and one-, five-, and
38 fifteen-minute exponentially-weighted moving average throughputs.
39
40 See:
41 - U{EMA
42 <http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average>}
43 """
44
45 MESSAGE = (
46 "stats.meter.%(key)s.count %(count)s %(timestamp)s\n"
47 "stats.meter.%(key)s.mean_rate %(mean_rate)s %(timestamp)s\n"
48 "stats.meter.%(key)s.1min_rate %(rate_1min)s %(timestamp)s\n"
49 "stats.meter.%(key)s.5min_rate %(rate_5min)s %(timestamp)s\n"
50 "stats.meter.%(key)s.15min_rate %(rate_15min)s %(timestamp)s\n")
51
52 def __init__(self, name, wall_time_func=time.time):
53 """Construct a metric we expect to be periodically updated.
54
55 @param name: Indicates what is being instrumented.
56 @param wall_time_func: Function for obtaining wall time.
57 """
58 self.name = name
59 self.wall_time_func = wall_time_func
60
61 self.m1_rate = Ewma.one_minute_ewma()
62 self.m5_rate = Ewma.five_minute_ewma()
63 self.m15_rate = Ewma.fifteen_minute_ewma()
64 self.count = 0
65 self.start_time = self.wall_time_func()
66
67 def mark(self, value=1):
68 """Mark the occurrence of a given number of events."""
69 self.count += value
70 self.m1_rate.update(value)
71 self.m5_rate.update(value)
72 self.m15_rate.update(value)
73
74 def tick(self):
75 """Updates the moving averages."""
76 self.m1_rate.tick()
77 self.m5_rate.tick()
78 self.m15_rate.tick()
79
80 def report(self, timestamp):
81 return MeterMetricReporter.MESSAGE % {
82 "key": self.name,
83 "count": self.count,
84 "mean_rate": self.mean_rate(),
85 "rate_1min": self.one_minute_rate(),
86 "rate_5min": self.five_minute_rate(),
87 "rate_15min": self.fifteen_minute_rate(),
88 "timestamp": timestamp}
89
90 def fifteen_minute_rate(self):
91 return self.m15_rate.rate
92
93 def five_minute_rate(self):
94 return self.m5_rate.rate
95
96 def one_minute_rate(self):
97 return self.m1_rate.rate
98
99 def mean_rate(self):
100 if self.count == 0:
101 return 0.0
102 else:
103 elapsed = self.wall_time_func() - self.start_time
104 return float(self.count) / elapsed
0105
=== modified file 'txstatsd/metrics/metrics.py'
--- txstatsd/metrics/metrics.py 2011-07-27 15:02:32 +0000
+++ txstatsd/metrics/metrics.py 2011-08-26 12:28:49 +0000
@@ -1,5 +1,6 @@
11
2from txstatsd.metrics.gaugemetric import GaugeMetric2from txstatsd.metrics.gaugemetric import GaugeMetric
3from txstatsd.metrics.metermetric import MeterMetric
3from txstatsd.metrics.metric import Metric4from txstatsd.metrics.metric import Metric
45
56
@@ -28,6 +29,16 @@
28 self._metrics[name] = gauge_metric29 self._metrics[name] = gauge_metric
29 self._metrics[name].mark(value)30 self._metrics[name].mark(value)
3031
32 def meter(self, name, value, sample_rate=1):
33 """Mark the occurrence of a given number of events."""
34 name = self.fully_qualify_name(name)
35 if not name in self._metrics:
36 meter_metric = MeterMetric(self.connection,
37 name,
38 sample_rate)
39 self._metrics[name] = meter_metric
40 self._metrics[name].mark(value)
41
31 def increment(self, name, value=1, sample_rate=1):42 def increment(self, name, value=1, sample_rate=1):
32 """Report and increase in name by count."""43 """Report and increase in name by count."""
33 name = self.fully_qualify_name(name)44 name = self.fully_qualify_name(name)
3445
=== modified file 'txstatsd/server/processor.py'
--- txstatsd/server/processor.py 2011-07-25 16:09:37 +0000
+++ txstatsd/server/processor.py 2011-08-26 12:28:49 +0000
@@ -5,6 +5,8 @@
55
6from twisted.python import log6from twisted.python import log
77
8from txstatsd.metrics.metermetric import MeterMetricReporter
9
810
9SPACES = re.compile("\s+")11SPACES = re.compile("\s+")
10SLASHES = re.compile("\/+")12SLASHES = re.compile("\/+")
@@ -43,6 +45,7 @@
43 self.timer_metrics = {}45 self.timer_metrics = {}
44 self.counter_metrics = {}46 self.counter_metrics = {}
45 self.gauge_metrics = deque()47 self.gauge_metrics = deque()
48 self.meter_metrics = {}
4649
47 def fail(self, message):50 def fail(self, message):
48 """Log and discard malformed message."""51 """Log and discard malformed message."""
@@ -72,6 +75,8 @@
72 self.process_timer_metric(key, fields[0], message)75 self.process_timer_metric(key, fields[0], message)
73 elif fields[1] == "g":76 elif fields[1] == "g":
74 self.process_gauge_metric(key, fields[0], message)77 self.process_gauge_metric(key, fields[0], message)
78 elif fields[1] == "m":
79 self.process_meter_metric(key, fields[0], message)
75 else:80 else:
76 return self.fail(message)81 return self.fail(message)
7782
@@ -110,6 +115,21 @@
110 except (TypeError, ValueError):115 except (TypeError, ValueError):
111 self.fail(message)116 self.fail(message)
112117
118 def process_meter_metric(self, key, composite, message):
119 values = composite.split(":")
120 if not len(values) == 1:
121 return self.fail(message)
122
123 try:
124 value = float(values[0])
125 except (TypeError, ValueError):
126 self.fail(message)
127
128 if not key in self.meter_metrics:
129 metric = MeterMetricReporter(key, self.time_function)
130 self.meter_metrics[key] = metric
131 self.meter_metrics[key].mark(value)
132
113 def flush(self, interval=10000, percent=90):133 def flush(self, interval=10000, percent=90):
114 """134 """
115 Flush all queued stats, computing a normalized count based on135 Flush all queued stats, computing a normalized count based on
@@ -136,6 +156,11 @@
136 messages.extend(gauge_metrics)156 messages.extend(gauge_metrics)
137 num_stats += events157 num_stats += events
138158
159 meter_metrics, events = self.flush_meter_metrics(timestamp)
160 if events > 0:
161 messages.extend(meter_metrics)
162 num_stats += events
163
139 messages.append("statsd.numStats %s %s" % (num_stats, timestamp))164 messages.append("statsd.numStats %s %s" % (num_stats, timestamp))
140 return messages165 return messages
141166
@@ -211,3 +236,17 @@
211 self.gauge_metrics.clear()236 self.gauge_metrics.clear()
212237
213 return (metrics, events)238 return (metrics, events)
239
240 def flush_meter_metrics(self, timestamp):
241 metrics = []
242 events = 0
243 for metric in self.meter_metrics.itervalues():
244 message = metric.report(timestamp)
245 metrics.append(message)
246 events += 1
247
248 return (metrics, events)
249
250 def update_metrics(self):
251 for metric in self.meter_metrics.itervalues():
252 metric.tick()
214253
=== modified file 'txstatsd/service.py'
--- txstatsd/service.py 2011-07-27 20:31:33 +0000
+++ txstatsd/service.py 2011-08-26 12:28:49 +0000
@@ -117,6 +117,12 @@
117 report_name.upper(), ()):117 report_name.upper(), ()):
118 reporting.schedule(reporter, 10, metrics.gauge)118 reporting.schedule(reporter, 10, metrics.gauge)
119119
120 # Schedule updates for those metrics expecting to be
121 # periodically updated, for example the meter metric.
122 metrics_updater = ReportingService()
123 metrics_updater.setServiceParent(service)
124 metrics_updater.schedule(processor.update_metrics, 5, None)
125
120 factory = GraphiteClientFactory(processor, options["flush-interval"])126 factory = GraphiteClientFactory(processor, options["flush-interval"])
121 client = TCPClient(options["carbon-cache-host"],127 client = TCPClient(options["carbon-cache-host"],
122 options["carbon-cache-port"],128 options["carbon-cache-port"],
123129
=== added directory 'txstatsd/stats'
=== added file 'txstatsd/stats/__init__.py'
=== added file 'txstatsd/stats/ewma.py'
--- txstatsd/stats/ewma.py 1970-01-01 00:00:00 +0000
+++ txstatsd/stats/ewma.py 2011-08-26 12:28:49 +0000
@@ -0,0 +1,70 @@
1
2"""
3An exponentially-weighted moving average.
4
5See:
6- U{UNIX Load Average Part 1: How It Works
7 <http://www.teamquest.com/pdfs/whitepaper/ldavg1.pdf>}
8- U{UNIX Load Average Part 2: Not Your Average Average
9 <http://www.teamquest.com/pdfs/whitepaper/ldavg2.pdf>}
10"""
11
12import math
13
14
15class Ewma(object):
16 M1_ALPHA = 1 - math.exp(-5 / 60.0)
17 M5_ALPHA = 1 - math.exp(-5 / 60.0 / 5)
18 M15_ALPHA = 1 - math.exp(-5 / 60.0 / 15)
19
20 @classmethod
21 def one_minute_ewma(cls):
22 """
23 Creates a new C{Ewma} which is equivalent to the UNIX one minute
24 load average and which expects to be ticked every 5 seconds.
25 """
26 return Ewma(Ewma.M1_ALPHA, 5)
27
28 @classmethod
29 def five_minute_ewma(cls):
30 """
31 Creates a new C{Ewma} which is equivalent to the UNIX five minute
32 load average and which expects to be ticked every 5 seconds.
33 """
34 return Ewma(Ewma.M5_ALPHA, 5)
35
36 @classmethod
37 def fifteen_minute_ewma(cls):
38 """
39 Creates a new C{Ewma} which is equivalent to the UNIX fifteen
40 minute load average and which expects to be ticked every 5 seconds.
41 """
42 return Ewma(Ewma.M15_ALPHA, 5)
43
44 def __init__(self, alpha, interval):
45 """Create a new C{Ewma} with a specific smoothing constant.
46
47 @param alpha: The smoothing constant.
48 @param interval: The expected tick interval in seconds.
49 """
50 self.interval = interval
51 self.alpha = float(alpha)
52
53 self.initialized = False
54 self.rate = 0.0
55 self.uncounted = 0
56
57 def update(self, n):
58 """Update the moving average with a new value."""
59 self.uncounted += n
60
61 def tick(self):
62 """Mark the passage of time and decay the current rate accordingly."""
63 count = self.uncounted
64 self.uncounted = 0
65 instant_rate = float(count) / self.interval
66 if self.initialized:
67 self.rate += (self.alpha * (instant_rate - self.rate))
68 else:
69 self.rate = instant_rate
70 self.initialized = True
071
=== added directory 'txstatsd/tests/stats'
=== added file 'txstatsd/tests/stats/__init__.py'
=== added file 'txstatsd/tests/stats/test_ewma.py'
--- txstatsd/tests/stats/test_ewma.py 1970-01-01 00:00:00 +0000
+++ txstatsd/tests/stats/test_ewma.py 2011-08-26 12:28:49 +0000
@@ -0,0 +1,315 @@
1
2import math
3from unittest import TestCase
4
5from txstatsd.stats.ewma import Ewma
6
7
8def mark_minutes(minutes, ewma):
9 for i in range(1, minutes * 60, 5):
10 ewma.tick()
11
12class TestEwmaOneMinute(TestCase):
13 def setUp(self):
14 self.ewma = Ewma.one_minute_ewma()
15 self.ewma.update(3)
16 self.ewma.tick()
17
18 def test_first_tick(self):
19 self.assertTrue(
20 (math.fabs(self.ewma.rate - 0.6) < 0.000001),
21 'Should have a rate of 0.6 events/sec after the first tick')
22
23 def test_one_minute(self):
24 mark_minutes(1, self.ewma)
25 self.assertTrue(
26 (math.fabs(self.ewma.rate - 0.22072766) < 0.00000001),
27 'Should have a rate of 0.22072766 events/sec after 1 minute')
28
29 def test_two_minutes(self):
30 mark_minutes(2, self.ewma)
31 self.assertTrue(
32 (math.fabs(self.ewma.rate - 0.08120117) < 0.00000001),
33 'Should have a rate of 0.08120117 events/sec after 2 minutes')
34
35 def test_three_minutes(self):
36 mark_minutes(3, self.ewma)
37 self.assertTrue(
38 (math.fabs(self.ewma.rate - 0.02987224) < 0.00000001),
39 'Should have a rate of 0.02987224 events/sec after 3 minutes')
40
41 def test_four_minutes(self):
42 mark_minutes(4, self.ewma)
43 self.assertTrue(
44 (math.fabs(self.ewma.rate - 0.01098938) < 0.00000001),
45 'Should have a rate of 0.01098938 events/sec after 4 minutes')
46
47 def test_five_minutes(self):
48 mark_minutes(5, self.ewma)
49 self.assertTrue(
50 (math.fabs(self.ewma.rate - 0.00404277) < 0.00000001),
51 'Should have a rate of 0.00404277 events/sec after 5 minutes')
52
53 def test_six_minutes(self):
54 mark_minutes(6, self.ewma)
55 self.assertTrue(
56 (math.fabs(self.ewma.rate - 0.00148725) < 0.00000001),
57 'Should have a rate of 0.00148725 events/sec after 6 minutes')
58
59 def test_seven_minutes(self):
60 mark_minutes(7, self.ewma)
61 self.assertTrue(
62 (math.fabs(self.ewma.rate - 0.00054713) < 0.00000001),
63 'Should have a rate of 0.00054713 events/sec after 7 minutes')
64
65 def test_eight_minutes(self):
66 mark_minutes(8, self.ewma)
67 self.assertTrue(
68 (math.fabs(self.ewma.rate - 0.00020128) < 0.00000001),
69 'Should have a rate of 0.00020128 events/sec after 8 minutes')
70
71 def test_nine_minutes(self):
72 mark_minutes(9, self.ewma)
73 self.assertTrue(
74 (math.fabs(self.ewma.rate - 0.00007405) < 0.00000001),
75 'Should have a rate of 0.00007405 events/sec after 9 minutes')
76
77 def test_ten_minutes(self):
78 mark_minutes(10, self.ewma)
79 self.assertTrue(
80 (math.fabs(self.ewma.rate - 0.00002724) < 0.00000001),
81 'Should have a rate of 0.00002724 events/sec after 10 minutes')
82
83 def test_eleven_minutes(self):
84 mark_minutes(11, self.ewma)
85 self.assertTrue(
86 (math.fabs(self.ewma.rate - 0.00001002) < 0.00000001),
87 'Should have a rate of 0.00001002 events/sec after 11 minutes')
88
89 def test_twelve_minutes(self):
90 mark_minutes(12, self.ewma)
91 self.assertTrue(
92 (math.fabs(self.ewma.rate - 0.00000369) < 0.00000001),
93 'Should have a rate of 0.00000369 events/sec after 12 minutes')
94
95 def test_thirteen_minutes(self):
96 mark_minutes(13, self.ewma)
97 self.assertTrue(
98 (math.fabs(self.ewma.rate - 0.00000136) < 0.00000001),
99 'Should have a rate of 0.00000136 events/sec after 13 minutes')
100
101 def test_fourteen_minutes(self):
102 mark_minutes(14, self.ewma)
103 self.assertTrue(
104 (math.fabs(self.ewma.rate - 0.00000050) < 0.00000001),
105 'Should have a rate of 0.00000050 events/sec after 14 minutes')
106
107 def test_fifteen_minutes(self):
108 mark_minutes(15, self.ewma)
109 self.assertTrue(
110 (math.fabs(self.ewma.rate - 0.00000018) < 0.00000001),
111 'Should have a rate of 0.00000018 events/sec after 15 minutes')
112
113
114class TestEwmaFiveMinute(TestCase):
115 def setUp(self):
116 self.ewma = Ewma.five_minute_ewma()
117 self.ewma.update(3)
118 self.ewma.tick()
119
120 def test_first_tick(self):
121 self.assertTrue(
122 (math.fabs(self.ewma.rate - 0.6) < 0.000001),
123 'Should have a rate of 0.6 events/sec after the first tick')
124
125 def test_one_minute(self):
126 mark_minutes(1, self.ewma)
127 self.assertTrue(
128 (math.fabs(self.ewma.rate - 0.49123845) < 0.00000001),
129 'Should have a rate of 0.49123845 events/sec after 1 minute')
130
131 def test_two_minutes(self):
132 mark_minutes(2, self.ewma)
133 self.assertTrue(
134 (math.fabs(self.ewma.rate - 0.40219203) < 0.00000001),
135 'Should have a rate of 0.40219203 events/sec after 2 minutes')
136
137 def test_three_minutes(self):
138 mark_minutes(3, self.ewma)
139 self.assertTrue(
140 (math.fabs(self.ewma.rate - 0.32928698) < 0.00000001),
141 'Should have a rate of 0.32928698 events/sec after 3 minutes')
142
143 def test_four_minutes(self):
144 mark_minutes(4, self.ewma)
145 self.assertTrue(
146 (math.fabs(self.ewma.rate - 0.26959738) < 0.00000001),
147 'Should have a rate of 0.26959738 events/sec after 4 minutes')
148
149 def test_five_minutes(self):
150 mark_minutes(5, self.ewma)
151 self.assertTrue(
152 (math.fabs(self.ewma.rate - 0.22072766) < 0.00000001),
153 'Should have a rate of 0.22072766 events/sec after 5 minutes')
154
155 def test_six_minutes(self):
156 mark_minutes(6, self.ewma)
157 self.assertTrue(
158 (math.fabs(self.ewma.rate - 0.18071653) < 0.00000001),
159 'Should have a rate of 0.18071653 events/sec after 6 minutes')
160
161 def test_seven_minutes(self):
162 mark_minutes(7, self.ewma)
163 self.assertTrue(
164 (math.fabs(self.ewma.rate - 0.14795818) < 0.00000001),
165 'Should have a rate of 0.14795818 events/sec after 7 minutes')
166
167 def test_eight_minutes(self):
168 mark_minutes(8, self.ewma)
169 self.assertTrue(
170 (math.fabs(self.ewma.rate - 0.12113791) < 0.00000001),
171 'Should have a rate of 0.12113791 events/sec after 8 minutes')
172
173 def test_nine_minutes(self):
174 mark_minutes(9, self.ewma)
175 self.assertTrue(
176 (math.fabs(self.ewma.rate - 0.09917933) < 0.00000001),
177 'Should have a rate of 0.09917933 events/sec after 9 minutes')
178
179 def test_ten_minutes(self):
180 mark_minutes(10, self.ewma)
181 self.assertTrue(
182 (math.fabs(self.ewma.rate - 0.08120117) < 0.00000001),
183 'Should have a rate of 0.08120117 events/sec after 10 minutes')
184
185 def test_eleven_minutes(self):
186 mark_minutes(11, self.ewma)
187 self.assertTrue(
188 (math.fabs(self.ewma.rate - 0.06648190) < 0.00000001),
189 'Should have a rate of 0.06648190 events/sec after 11 minutes')
190
191 def test_twelve_minutes(self):
192 mark_minutes(12, self.ewma)
193 self.assertTrue(
194 (math.fabs(self.ewma.rate - 0.05443077) < 0.00000001),
195 'Should have a rate of 0.05443077 events/sec after 12 minutes')
196
197 def test_thirteen_minutes(self):
198 mark_minutes(13, self.ewma)
199 self.assertTrue(
200 (math.fabs(self.ewma.rate - 0.04456415) < 0.00000001),
201 'Should have a rate of 0.04456415 events/sec after 13 minutes')
202
203 def test_fourteen_minutes(self):
204 mark_minutes(14, self.ewma)
205 self.assertTrue(
206 (math.fabs(self.ewma.rate - 0.03648604) < 0.00000001),
207 'Should have a rate of 0.03648604 events/sec after 14 minutes')
208
209 def test_fifteen_minutes(self):
210 mark_minutes(15, self.ewma)
211 self.assertTrue(
212 (math.fabs(self.ewma.rate - 0.02987224) < 0.00000001),
213 'Should have a rate of 0.02987224 events/sec after 15 minutes')
214
215
216class TestEwmaFifteenMinute(TestCase):
217 def setUp(self):
218 self.ewma = Ewma.fifteen_minute_ewma()
219 self.ewma.update(3)
220 self.ewma.tick()
221
222 def test_first_tick(self):
223 self.assertTrue(
224 (math.fabs(self.ewma.rate - 0.6) < 0.000001),
225 'Should have a rate of 0.6 events/sec after the first tick')
226
227 def test_one_minute(self):
228 mark_minutes(1, self.ewma)
229 self.assertTrue(
230 (math.fabs(self.ewma.rate - 0.56130419) < 0.00000001),
231 'Should have a rate of 0.56130419 events/sec after 1 minute')
232
233 def test_two_minutes(self):
234 mark_minutes(2, self.ewma)
235 self.assertTrue(
236 (math.fabs(self.ewma.rate - 0.52510399) < 0.00000001),
237 'Should have a rate of 0.52510399 events/sec after 2 minutes')
238
239 def test_three_minutes(self):
240 mark_minutes(3, self.ewma)
241 self.assertTrue(
242 (math.fabs(self.ewma.rate - 0.49123845) < 0.00000001),
243 'Should have a rate of 0.49123845 events/sec after 3 minutes')
244
245 def test_four_minutes(self):
246 mark_minutes(4, self.ewma)
247 self.assertTrue(
248 (math.fabs(self.ewma.rate - 0.45955700) < 0.00000001),
249 'Should have a rate of 0.45955700 events/sec after 4 minutes')
250
251 def test_five_minutes(self):
252 mark_minutes(5, self.ewma)
253 self.assertTrue(
254 (math.fabs(self.ewma.rate - 0.42991879) < 0.00000001),
255 'Should have a rate of 0.42991879 events/sec after 5 minutes')
256
257 def test_six_minutes(self):
258 mark_minutes(6, self.ewma)
259 self.assertTrue(
260 (math.fabs(self.ewma.rate - 0.40219203) < 0.00000001),
261 'Should have a rate of 0.40219203 events/sec after 6 minutes')
262
263 def test_seven_minutes(self):
264 mark_minutes(7, self.ewma)
265 self.assertTrue(
266 (math.fabs(self.ewma.rate - 0.37625345) < 0.00000001),
267 'Should have a rate of 0.37625345 events/sec after 7 minutes')
268
269 def test_eight_minutes(self):
270 mark_minutes(8, self.ewma)
271 self.assertTrue(
272 (math.fabs(self.ewma.rate - 0.35198773) < 0.00000001),
273 'Should have a rate of 0.35198773 events/sec after 8 minutes')
274
275 def test_nine_minutes(self):
276 mark_minutes(9, self.ewma)
277 self.assertTrue(
278 (math.fabs(self.ewma.rate - 0.32928698) < 0.00000001),
279 'Should have a rate of 0.32928698 events/sec after 9 minutes')
280
281 def test_ten_minutes(self):
282 mark_minutes(10, self.ewma)
283 self.assertTrue(
284 (math.fabs(self.ewma.rate - 0.30805027) < 0.00000001),
285 'Should have a rate of 0.30805027 events/sec after 10 minutes')
286
287 def test_eleven_minutes(self):
288 mark_minutes(11, self.ewma)
289 self.assertTrue(
290 (math.fabs(self.ewma.rate - 0.28818318) < 0.00000001),
291 'Should have a rate of 0.28818318 events/sec after 11 minutes')
292
293 def test_twelve_minutes(self):
294 mark_minutes(12, self.ewma)
295 self.assertTrue(
296 (math.fabs(self.ewma.rate - 0.26959738) < 0.00000001),
297 'Should have a rate of 0.26959738 events/sec after 12 minutes')
298
299 def test_thirteen_minutes(self):
300 mark_minutes(13, self.ewma)
301 self.assertTrue(
302 (math.fabs(self.ewma.rate - 0.25221023) < 0.00000001),
303 'Should have a rate of 0.25221023 events/sec after 13 minutes')
304
305 def test_fourteen_minutes(self):
306 mark_minutes(14, self.ewma)
307 self.assertTrue(
308 (math.fabs(self.ewma.rate - 0.23594443) < 0.00000001),
309 'Should have a rate of 0.23594443 events/sec after 14 minutes')
310
311 def test_fifteen_minutes(self):
312 mark_minutes(15, self.ewma)
313 self.assertTrue(
314 (math.fabs(self.ewma.rate - 0.22072766) < 0.00000001),
315 'Should have a rate of 0.22072766 events/sec after 15 minutes')
0316
=== modified file 'txstatsd/tests/test_metrics.py'
--- txstatsd/tests/test_metrics.py 2011-07-03 11:49:05 +0000
+++ txstatsd/tests/test_metrics.py 2011-08-26 12:28:49 +0000
@@ -32,6 +32,12 @@
32 self.assertEqual(self.connection.data,32 self.assertEqual(self.connection.data,
33 'txstatsd.tests.gauge:102|g')33 'txstatsd.tests.gauge:102|g')
3434
35 def test_meter(self):
36 """Test reporting of a meter metric sample."""
37 self.metrics.meter('meter', 3)
38 self.assertEqual(self.connection.data,
39 'txstatsd.tests.meter:3|m')
40
35 def test_counter(self):41 def test_counter(self):
36 """Test the increment and decrement operations."""42 """Test the increment and decrement operations."""
37 self.metrics.increment('counter', 18)43 self.metrics.increment('counter', 18)
3844
=== modified file 'txstatsd/tests/test_processor.py'
--- txstatsd/tests/test_processor.py 2011-07-04 03:00:04 +0000
+++ txstatsd/tests/test_processor.py 2011-08-26 12:28:49 +0000
@@ -1,3 +1,5 @@
1import time
2
1from unittest import TestCase3from unittest import TestCase
24
3from txstatsd.server.processor import MessageProcessor5from txstatsd.server.processor import MessageProcessor
@@ -224,3 +226,73 @@
224 self.assertEqual(226 self.assertEqual(
225 "statsd.numStats 1 42", messages[1])227 "statsd.numStats 1 42", messages[1])
226 self.assertEqual(0, len(self.processor.gauge_metrics))228 self.assertEqual(0, len(self.processor.gauge_metrics))
229
230
231class FlushMeterMetricMessagesTest(TestCase):
232
233 def setUp(self):
234 self.processor = MessageProcessor(time_function=self.wall_clock_time)
235 self.time_now = int(time.time())
236
237 def wall_clock_time(self):
238 return self.time_now
239
240 def mark_minutes(self, minutes):
241 for i in range(1, minutes * 60, 5):
242 self.processor.update_metrics()
243
244 def test_flush_meter_metric(self):
245 """
246 Test the correct rendering of the Graphite report for
247 a meter metric.
248 """
249 self.processor.process("gorets:3.0|m")
250
251 self.time_now += 1
252 messages = self.processor.flush()
253 self.assertEqual(2, len(messages))
254 meter_metric = messages[0].splitlines()
255 self.assertEqual(
256 "stats.meter.gorets.count 3.0 %s" % self.time_now,
257 meter_metric[0])
258 self.assertEqual(
259 "stats.meter.gorets.mean_rate 3.0 %s" % self.time_now,
260 meter_metric[1])
261 self.assertEqual(
262 "stats.meter.gorets.1min_rate 0.0 %s" % self.time_now,
263 meter_metric[2])
264 self.assertEqual(
265 "stats.meter.gorets.5min_rate 0.0 %s" % self.time_now,
266 meter_metric[3])
267 self.assertEqual(
268 "stats.meter.gorets.15min_rate 0.0 %s" % self.time_now,
269 meter_metric[4])
270 self.assertEqual(
271 "statsd.numStats 1 %s" % self.time_now, messages[1])
272
273 # As we are employing the expected results from test_ewma.py
274 # we perform the initial tick(), before advancing the clock 60sec.
275 self.processor.update_metrics()
276
277 self.mark_minutes(1)
278 self.time_now += 60
279 messages = self.processor.flush()
280 self.assertEqual(2, len(messages))
281 meter_metric = messages[0].splitlines()
282 self.assertEqual(
283 "stats.meter.gorets.count 3.0 %s" % self.time_now,
284 meter_metric[0])
285 self.assertTrue(
286 meter_metric[1].startswith(
287 "stats.meter.gorets.mean_rate 0.04918032"))
288 self.assertTrue(
289 meter_metric[2].startswith(
290 "stats.meter.gorets.1min_rate 0.22072766"))
291 self.assertTrue(
292 meter_metric[3].startswith(
293 "stats.meter.gorets.5min_rate 0.49123845"))
294 self.assertTrue(
295 meter_metric[4].startswith(
296 "stats.meter.gorets.15min_rate 0.5613041"))
297 self.assertEqual(
298 "statsd.numStats 1 %s" % self.time_now, messages[1])
227299
=== modified file 'txstatsd/version.py'
--- txstatsd/version.py 2011-08-23 02:05:21 +0000
+++ txstatsd/version.py 2011-08-26 12:28:49 +0000
@@ -1,1 +1,1 @@
1txstatsd = "0.1.3"1txstatsd = "0.2.0"

Subscribers

People subscribed via source and target branches