Merge lp:~caravone/txstatsd/statsd-timings-consistency into lp:txstatsd

Proposed by Curtis Caravone
Status: Merged
Approved by: Curtis Caravone
Approved revision: 56
Merged at revision: 54
Proposed branch: lp:~caravone/txstatsd/statsd-timings-consistency
Merge into: lp:txstatsd
Diff against target: 100 lines (+32/-9)
5 files modified
txstatsd/metrics/extendedmetrics.py (+4/-2)
txstatsd/metrics/imetrics.py (+2/-2)
txstatsd/metrics/metrics.py (+9/-4)
txstatsd/metrics/timermetric.py (+1/-1)
txstatsd/tests/test_metrics.py (+16/-0)
To merge this branch: bzr merge lp:~caravone/txstatsd/statsd-timings-consistency
Reviewer Review Type Date Requested Status
Sidnei da Silva Approve
Review via email: mp+83645@code.launchpad.net

This proposal supersedes a proposal from 2011-11-26.

Commit message

Added timing consistency (always take seconds but emit milliseconds) to ExtendedMetrics.
Added automatic timing option to ExtendedMetrics and signature of IMetrics timing methods.

Description of the change

Updated Nov. 28, 2011:

Made sure ExtendedMetrics and IMetrics had the updated timing() logic as well. Added unit tests for ExtendedMetrics.

Changed timing() method to clearly take durations in seconds and emit durations to txstatsd server in milliseconds
Add option for automatic calculation of timing duration

To post a comment you must log in.
Revision history for this message
Sidnei da Silva (sidnei) wrote : Posted in a previous version of this proposal

Looks good. Thanks!

One thing I noticed is that we're storing instance-level attributes here and in other metrics. Which means that we can't safely use them from different threads. We need to make sure that we use a per-thread metrics object in client code, or maybe handle the thread-safety here so the client code doesn't have to bother.

review: Approve
Revision history for this message
Curtis Caravone (caravone) wrote : Posted in a previous version of this proposal

For the timer code I added, it would probably make sense to use a
thread-bound variable, since timing an activity generally makes the most
sense in the context of a thread. I'll take a look at the other uses of
instance-level attributes used and see what would appear to make the
most sense.

Curtis

On 11/26/11 7:34 AM, Sidnei da Silva wrote:
> Review: Approve
>
> Looks good. Thanks!
>
> One thing I noticed is that we're storing instance-level attributes here and in other metrics. Which means that we can't safely use them from different threads. We need to make sure that we use a per-thread metrics object in client code, or maybe handle the thread-safety here so the client code doesn't have to bother.

Revision history for this message
Sidnei da Silva (sidnei) wrote :

Please use no spaces around the equals sign on function arguments.

Other than that looks good. Once you fix that, please set a commit message in this MP and flip the status to Approved.

review: Approve
Revision history for this message
Curtis Caravone (caravone) wrote :

One thing I wasn't sure about was the expected behavior of the increment/decrement calls. As you can see from the unit tests, the basic Metrics object emits deltas for each increment/decrements, while the ExtendedMetrics version keeps a cumulative delta and emits that. Not sure if it's a bug or just a subtlety of the API.

56. By Curtis Caravone

Formatting: Removed spaces around '=' in default function arguments

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'txstatsd/metrics/extendedmetrics.py'
2--- txstatsd/metrics/extendedmetrics.py 2011-09-14 12:01:10 +0000
3+++ txstatsd/metrics/extendedmetrics.py 2011-11-28 17:18:41 +0000
4@@ -39,8 +39,10 @@
5 self._metrics[name] = metric
6 self._metrics[name].decrement(value)
7
8- def timing(self, name, duration, sample_rate=1):
9- """Report this sample performed in duration ms."""
10+ def timing(self, name, duration=None, sample_rate=1):
11+ """Report this sample performed in duration seconds."""
12+ if duration is None:
13+ duration = self.calculate_duration()
14 name = self.fully_qualify_name(name)
15 if not name in self._metrics:
16 metric = TimerMetric(self.connection,
17
18=== modified file 'txstatsd/metrics/imetrics.py'
19--- txstatsd/metrics/imetrics.py 2011-09-09 15:49:55 +0000
20+++ txstatsd/metrics/imetrics.py 2011-11-28 17:18:41 +0000
21@@ -14,5 +14,5 @@
22 def decrement(name, value=1, sample_rate=1):
23 """Decrement counter C{name} by C{count}."""
24
25- def timing(name, duration, sample_rate=1):
26- """Report that C{name} took C{duration} milliseconds."""
27+ def timing(name, duration=None, sample_rate=1):
28+ """Report that C{name} took C{duration} seconds."""
29
30=== modified file 'txstatsd/metrics/metrics.py'
31--- txstatsd/metrics/metrics.py 2011-11-25 23:56:31 +0000
32+++ txstatsd/metrics/metrics.py 2011-11-28 17:18:41 +0000
33@@ -90,14 +90,19 @@
34 """Resets the duration timer for the next call to timing()"""
35 self.last_time = time.time()
36
37- def timing(self, name, duration = None, sample_rate=1):
38+ def calculate_duration(self):
39+ """Resets the duration timer and returns the elapsed duration"""
40+ current_time = time.time()
41+ duration = current_time - self.last_time
42+ self.last_time = current_time
43+ return duration
44+
45+ def timing(self, name, duration=None, sample_rate=1):
46 """Report that this sample performed in duration seconds.
47 Default duration is the actual elapsed time since
48 the last call to this method or reset_timing()"""
49 if duration is None:
50- current_time = time.time()
51- duration = current_time - self.last_time
52- self.last_time = current_time
53+ duration = self.calculate_duration()
54 name = self.fully_qualify_name(name)
55 if not name in self._metrics:
56 metric = Metric(self.connection,
57
58=== modified file 'txstatsd/metrics/timermetric.py'
59--- txstatsd/metrics/timermetric.py 2011-09-14 12:01:10 +0000
60+++ txstatsd/metrics/timermetric.py 2011-11-28 17:18:41 +0000
61@@ -30,7 +30,7 @@
62
63 def mark(self, duration):
64 """Report this sample performed in duration (measured in seconds)."""
65- self.send("%s|ms" % duration)
66+ self.send("%s|ms" % (duration * 1000))
67
68
69 class TimerMetricReporter(object):
70
71=== modified file 'txstatsd/tests/test_metrics.py'
72--- txstatsd/tests/test_metrics.py 2011-11-25 23:56:31 +0000
73+++ txstatsd/tests/test_metrics.py 2011-11-28 17:18:41 +0000
74@@ -3,6 +3,7 @@
75 import re
76 import time
77 from unittest import TestCase
78+from txstatsd.metrics.extendedmetrics import ExtendedMetrics
79 from txstatsd.metrics.metrics import Metrics
80
81
82@@ -102,3 +103,18 @@
83 self.assertEqual(self.connection.data,
84 'gauge:413|g')
85
86+
87+class TestExtendedMetrics(TestMetrics):
88+ def setUp(self):
89+ super(TestExtendedMetrics, self).setUp()
90+ self.metrics = ExtendedMetrics(self.connection, 'txstatsd.tests')
91+
92+ def test_counter(self):
93+ """Test the increment and decrement operations."""
94+ self.metrics.increment('counter', 18)
95+ self.assertEqual(self.connection.data,
96+ 'txstatsd.tests.counter:18|c')
97+ self.metrics.decrement('counter', 9)
98+ self.assertEqual(self.connection.data,
99+ 'txstatsd.tests.counter:9|c')
100+

Subscribers

People subscribed via source and target branches